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()
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()
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)
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
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()