def check_external_attr(self, node, attr): if attr.args is not None: msg = 'external attribute takes no arguments' raise DumbTypeError(msg, loc=attr.loc) if node.body is not None: msg = ('function with external attribute should ' 'define only prototype') raise DumbTypeError(msg, loc=node.loc)
def _validate_logical_binop(node, left_ty, right_ty): if node.op in (Operator.EQ, Operator.NE): return if left_ty != BuiltinTypes.BOOL or right_ty != BuiltinTypes.BOOL: msg = 'invalid operand types to logical expression (%r and %r)' % ( left_ty.name, right_ty.name) raise DumbTypeError(msg, loc=node.loc)
def visit_BinaryOp(self, node): op = node.op left_ty = self.visit(node.left) right_ty = self.visit(node.right) result_ty = _builtin_type_conversion(left_ty, right_ty) if result_ty is None: msg = 'invalid operands to binary expression (%r and %r)' % ( left_ty.name, right_ty.name) raise DumbTypeError(msg, loc=node.loc) if Operator.logical(op): _validate_logical_binop(node, left_ty, right_ty) elif Operator.bitwise(op): _validate_bitwise_binop(node, left_ty, right_ty) elif Operator.shift(op): _validate_shift_binop(node, left_ty, right_ty) else: _validate_arithmetic_binop(node, left_ty, right_ty) # Promote left and right operand to the common type. node.ty = result_ty left_promote_ty = _builtin_type_promotion(left_ty, result_ty) right_promote_ty = _builtin_type_promotion(right_ty, result_ty) if left_promote_ty: node.left = ast.Cast(node.left, left_promote_ty, left_ty) if right_promote_ty: node.right = ast.Cast(node.right, right_promote_ty, right_ty) if Operator.relational(op): result_ty = BuiltinTypes.BOOL return result_ty
def visit_If(self, node): cond_ty = self.visit(node.cond) if cond_ty != BuiltinTypes.BOOL: msg = "condition expression must be of the type 'bool'" raise DumbTypeError(msg, loc=node.loc) self.visit(node.then) if node.otherwise is not None: self.visit(node.otherwise)
def visit_Var(self, node): value_ty = self.visit(node.initial_value) if not node.ty: node.ty = value_ty elif node.ty not in BuiltinTypes.VAR_TYPES: raise DumbTypeError('unknown type %r' % node.ty.name, loc=node.loc) if node.ty != value_ty: promote_to = _builtin_type_promotion(value_ty, node.ty) if promote_to: node.initial_value = ast.Cast(node.initial_value, promote_to, value_ty) else: msg = 'cannot implicitly cast %r to %r' % ( value_ty.name, node.ty.name) raise DumbTypeError(msg, loc=node.loc) self.symbol_table.set(node.name, node.ty)
def visit_Return(self, node): proto = self.curr_function.proto if proto.ret_ty == BuiltinTypes.VOID and node.value is not None: msg = 'unexpected return value' raise DumbTypeError(msg, loc=node.loc) if proto.ret_ty != BuiltinTypes.VOID and node.value is None: msg = 'expected %r return value' % proto.ret_ty.name raise DumbTypeError(msg, loc=node.loc) if not node.value: return value_ty = self.visit(node.value) if value_ty == proto.ret_ty: return promote_to = _builtin_type_promotion(value_ty, proto.ret_ty) if not promote_to: msg = 'cannot implicitly cast %r to %r' % ( value_ty.name, proto.ret_ty.name) raise DumbTypeError(msg, loc=node.loc) node.value = ast.Cast(node.value, proto.ret_ty, value_ty, loc=node.loc)
def visit_TranslationUnit(self, node): for decl in node.decls: if not isinstance(decl, ast.Function): # pragma: nocover continue if decl.proto.name == 'main': if decl.proto.ret_ty != ast.BuiltinTypes.I32: msg = 'main function has to return i32' raise DumbTypeError(msg, loc=decl.loc) return raise DumbNameError('no main func was found')
def visit_FuncCall(self, node): func = self.func_table.get(node.name) if not func: msg = 'name %r is not defined' % node.name raise DumbNameError(msg, loc=node.loc) proto = func.proto if len(node.args) != len(proto.args): msg = '%s() takes %d arguments (%d given)' % ( proto.name, len(proto.args), len(node.args)) raise DumbTypeError(msg, loc=node.loc) for i, value in enumerate(node.args): arg_ty = proto.args[i].ty value_ty = self.visit(value) if arg_ty == value_ty: continue promote_to = _builtin_type_promotion(value_ty, arg_ty) if not promote_to: msg = 'cannot implicitly cast %r to %r' % ( value_ty.name, arg_ty.name) raise DumbTypeError(msg, loc=node.loc) node.args[i] = ast.Cast(value, arg_ty, value_ty) return proto.ret_ty
def visit_Function(self, node): self.symbol_table.push() for arg in node.proto.args: if self.symbol_table.has(arg.name): msg = 'name %r has been defined' % arg.name raise DumbNameError(msg, loc=arg.loc) if arg.ty == BuiltinTypes.VOID: msg = 'invalid argument type (%r)' % arg.ty.name raise DumbTypeError(msg, loc=arg.loc) self.symbol_table.set(arg.name, arg.ty) if node.body: self.curr_function = node self.visit(node.body) self.curr_function = None self.symbol_table.pop()
def visit_Assignment(self, node): lvalue_ty = self.visit(node.lvalue) rvalue_ty = self.visit(node.rvalue) node.ty = lvalue_ty _validate_assignment(node, lvalue_ty, rvalue_ty) if node.op is not None: expr = ast.BinaryOp(node.op, node.lvalue, node.rvalue, loc=node.loc) self.visit(expr) if lvalue_ty == rvalue_ty: return lvalue_ty promote_to = _builtin_type_promotion(rvalue_ty, lvalue_ty) if not promote_to: msg = 'cannot implicitly cast %r to %r' % ( rvalue_ty.name, lvalue_ty.name) raise DumbTypeError(msg, loc=node.loc) node.rvalue = ast.Cast(node.rvalue, lvalue_ty, rvalue_ty) return lvalue_ty
def check_no_attrs(self, node): if node.body is None: msg = 'function body expected %r' % node.proto.name raise DumbTypeError(msg, loc=node.loc)
def _validate_assignment(node, left_ty, right_ty): if not isinstance(node.lvalue, ast.Identifier): msg = 'lvalue required as left operand of assignment' raise DumbTypeError(msg, loc=node.loc)
def _validate_logical_not_unaryop(node, value_ty): if value_ty != BuiltinTypes.BOOL: msg = 'invalid operand type %r' % value_ty.name raise DumbTypeError(msg, loc=node.loc)
def _validate_shift_binop(node, left_ty, right_ty): integer_types = BuiltinTypes.INTEGERS if left_ty not in integer_types or right_ty not in integer_types: msg = 'invalid operands to shift expression (%r and %r)' % ( left_ty.name, right_ty.name) raise DumbTypeError(msg, loc=node.loc)
def _validate_not_unaryop(node, value_ty): if value_ty not in BuiltinTypes.INTEGERS: msg = 'invalid operand type %r (integer type expected)' % value_ty.name raise DumbTypeError(msg, loc=node.loc)
def _validate_arithmetic_unaryop(node, value_ty): if value_ty not in BuiltinTypes.NUMERICAL: msg = 'invalid operand type %r (integral type expected)' % value_ty.name raise DumbTypeError(msg, loc=node.loc)
def visit_While(self, node): cond_ty = self.visit(node.cond) if cond_ty != BuiltinTypes.BOOL: msg = "condition expression must be of the type 'bool'" raise DumbTypeError(msg, loc=node.loc) self.visit(node.body)
def _validate_cast(node, src_ty, dst_ty): if dst_ty in (BuiltinTypes.STR, BuiltinTypes.VOID): msg = 'invalid type' raise DumbTypeError(msg, loc=node.loc)
def _validate_arithmetic_binop(node, left_ty, right_ty): numerical_types = BuiltinTypes.NUMERICAL if left_ty not in numerical_types or right_ty not in numerical_types: msg = 'invalid operands to arithmetic expression (%r and %r)' % ( left_ty.name, right_ty.name) raise DumbTypeError(msg, loc=node.loc)