Beispiel #1
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     for arg in expr.arguments:
         if not isinstance(arg.type, T.Boolean):
             raise Error.IncompatibleOperand(arg, "non-Boolean operand to ||")
         if expr._check_quant and arg.type.optional:
             raise Error.IncompatibleOperand(arg, "optional Boolean? operand to ||")
     return T.Boolean()
Beispiel #2
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     if (
         (
             expr._check_quant
             and expr.arguments[0].type.optional != expr.arguments[1].type.optional
         )
         or (
             self.name not in ["==", "!="]
             and (expr.arguments[0].type.optional or expr.arguments[1].type.optional)
         )
         or (
             not (
                 expr.arguments[0].type.copy(optional=False)
                 == expr.arguments[1].type.copy(optional=False)
                 or (
                     isinstance(expr.arguments[0].type, T.Int)
                     and isinstance(expr.arguments[1].type, T.Float)
                 )
                 or (
                     isinstance(expr.arguments[0].type, T.Float)
                     and isinstance(expr.arguments[1].type, T.Int)
                 )
             )
         )
     ):
         raise Error.IncompatibleOperand(
             expr,
             "Cannot compare {} and {}".format(
                 str(expr.arguments[0].type), str(expr.arguments[1].type)
             ),
         )
     return T.Boolean()
Beispiel #3
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     ans_type = self.infer_type(expr)
     try:
         ans = self.op(arguments[0].coerce(ans_type).value, arguments[1].coerce(ans_type).value)
     except ZeroDivisionError:
         # TODO: different runtime error?
         raise Error.IncompatibleOperand(expr.arguments[1], "Division by zero") from None
     if ans_type == T.Int():
         assert isinstance(ans, int)
         return V.Int(ans)
     assert isinstance(ans, float)
     return V.Float(ans)
Beispiel #4
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     rt = T.Int()
     if isinstance(expr.arguments[0].type, T.Float) or isinstance(
             expr.arguments[1].type, T.Float):
         rt = T.Float()
     try:
         expr.arguments[0].typecheck(rt)
         expr.arguments[1].typecheck(rt)
     except Error.StaticTypeMismatch:
         raise Error.IncompatibleOperand(
             expr,
             "Non-numeric operand to " + self.name + " operator") from None
     return rt
Beispiel #5
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     t2 = None
     if isinstance(expr.arguments[0].type, T.String):
         t2 = expr.arguments[1].type
     elif isinstance(expr.arguments[1].type, T.String):
         t2 = expr.arguments[0].type
     if t2 is None:
         # neither operand is a string; defer to _ArithmeticOperator
         return super().infer_type(expr)
     if not t2.coerces(T.String(optional=True)):
         raise Error.IncompatibleOperand(
             expr,
             "Cannot add/concatenate {} and {}".format(
                 str(expr.arguments[0].type), str(expr.arguments[1].type)),
         )
     return T.String()