def visit(self, node, scope): if node.type in build_in_types: self.errors.append(f'It cannot be initialized a {node.type} with the new keyword') node.computed_type = ErrorType() else: try: node_type = self.context.get_type(node.type) except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() node.computed_type = node_type
def visit(self, node, scope): self.visit(node.expr, scope) expr_type = node.expr.computed_type if scope.is_defined(node.id): var = scope.find_variable(node.id) node_type = var.type if var.name == 'self': self.errors.append(SELF_IS_READONLY) else: if IsAuto(node_type.name): if not IsAuto(expr_type.name): node.type = expr_type.name scope.find_variable(node.id).type = expr_type node.computed_type = expr_type else: if not IsAuto(expr_type.name): if not expr_type.conforms_to(node_type): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1)) else: self.update(node.expr, scope, node_type) node.computed_type = node.expr.computed_type else: self.errors.append(VARIABLE_NOT_DEFINED.replace('%s', node.id, 1).replace('%s', self.current_method.name, 1)) node.computed_type = ErrorType()
def visit(self, node, scope): self.visit(node.expr, scope) if not (IsAuto(node.expr.computed_type.name) or node.expr.computed_type.name != 'Int'): self.errors.append("Complement works only for Int") node.computed_type = ErrorType() else: node.computed_type = self.context.get_type('Int')
def visit(self, node, scope): obj_type = self.current_type try: obj_method = obj_type.get_method(node.id) if len(node.args) == len(obj_method.param_types): for idx, arg in enumerate(node.args): self.visit(arg, scope) arg_type = arg.computed_type param_type = obj_method.param_types[idx] if IsAuto(param_type.name): if not IsAuto(arg_type.name): obj_method.param_types[idx] = arg_type else: if IsAuto(arg_type.name): self.update(arg, scope, param_type) else: if not arg_type.conforms_to(param_type): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', arg_type.name, 1).replace('%s', param_type.name, 1)) else: self.errors.append(f'Method "{obj_method.name}" of "{obj_type.name}" only accepts {len(obj_method.param_types)} argument(s)') node_type = obj_method.return_type except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() node.computed_type = node_type
def visit(self, node, scope): self.visit(node.expr, scope) if not (IsAuto(node.expr.computed_type.name) or node.expr.computed_type.name != 'Bool'): self.errors.append("Not operator works only for Bool") node.computed_type = ErrorType() else: node.computed_type = self.context.get_type('Bool')
def visit(self, node, scope): node.scope = scope try: node_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() if not scope.is_local(node.id): scope.define_variable(node.id, node_type) else: self.errors.append(LOCAL_ALREADY_DEFINED.replace('%s', node.id, 1).replace('%s', self.current_method.name, 1)) if not node.expr: node.computed_type = node_type return self.visit(node.expr, scope) expr_type = node.expr.computed_type if IsAuto(node_type.name): if not IsAuto(expr_type.name): node.type = expr_type.name scope.find_variable(node.id).type = expr_type node.computed_type = expr_type else: if not IsAuto(expr_type.name): if not expr_type.conforms_to(node_type): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1)) else: self.update(node.expr, scope, node_type) node.computed_type = node.expr.computed_type
def visit(self, node, scope): self.visit(node.obj, scope) obj_type = node.obj.computed_type if node.type: try: if IsAuto(node.type): raise SemanticError('Is not possible to use AUTO_TYPE in a cast') if not obj_type.conforms_to(self.context.get_type(node.type)): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', obj_type.name, 1).replace('%s', node.type, 1)) except SemanticError as ex: self.errors.append(ex.text) try: if node.type: obj_method = self.context.get_type(node.type).get_method(node.id) else: obj_method = obj_type.get_method(node.id) if len(node.args) == len(obj_method.param_types): for arg, param_type in zip(node.args, obj_method.param_types): self.visit(arg, scope) arg_type = arg.computed_type if not (IsAuto(arg_type.name) or arg_type.conforms_to(param_type)): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', arg_type.name, 1).replace('%s', param_type.name, 1)) else: self.errors.append(f'Method "{obj_method.name}" of "{obj_type.name}" only accepts {len(obj_method.param_types)} argument(s)') node_type = obj_method.return_type except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() node.computed_type = node_type
def visit(self, node, scope): try: node_type = self.context.get_type(node.type) except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() node.computed_type = node_type
def visit(self, node, scope): if scope.is_defined(node.lex): var = scope.find_variable(node.lex) node_type = var.type else: self.errors.append(VARIABLE_NOT_DEFINED.replace('%s', node.lex, 1).replace('%s', self.current_method.name, 1)) node_type = ErrorType() node.computed_type = node_type
def visit(self, node): try: attr_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type except SemanticError as ex: self.errors.append(ex.text) attr_type = ErrorType() try: self.current_type.define_attribute(node.id, attr_type) except SemanticError as ex: self.errors.append(ex.text)
def visit(self, node): arg_names, arg_types = [], [] for idx, typex in node.params: try: arg_type = self.context.get_type(typex) if node.type != 'SELF_TYPE' else self.current_type except SemanticError as ex: self.errors.append(ex.text) arg_type = ErrorType() arg_names.append(idx) arg_types.append(arg_type) try: ret_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type except SemanticError as ex: self.errors.append(ex.text) ret_type = ErrorType() try: self.current_type.define_method(node.id, arg_names, arg_types, ret_type) except SemanticError as ex: self.errors.append(ex.text)
def visit(self, node, scope): self.visit(node.left, scope) left_type = node.left.computed_type self.visit(node.right, scope) right_type = node.right.computed_type if not (IsAuto(left_type.name) or left_type.conforms_to(IntType())) or not (IsAuto(right_type.name) or right_type.conforms_to(IntType())): self.errors.append(INVALID_OPERATION.replace('%s', left_type.name, 1).replace('%s', right_type.name, 1)) node_type = ErrorType() else: node_type = IntType() node.computed_type = node_type
def visit(self, node, scope): self.visit(node.expr, scope) has_auto = has_error = False types_list = [] for case in node.branches: self.visit(case.expr, scope) has_auto |= IsAuto(case.expr.computed_type.name) has_error |= case.expr.computed_type.name == '<error>' types_list.append(case.expr.computed_type) if has_error: node.computed_type = ErrorType() elif has_auto: node.computed_type = self.context.get_type('AUTO_TYPE') else: node.computed_type = LCA(types_list, self.context)
def visit(self, node, scope): node.scope = scope if node.expr: self.visit(node.expr, scope) if IsAuto(node.type): if not IsAuto(node.expr.computed_type.name): scope.find_variable(node.id).type = node.expr.computed_type else: if IsAuto(node.expr.computed_type.name): self.update(node.expr, scope, node.type) else: if not node.expr.computed_type.conforms_to(node.computed_type): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', node.expr.computed_type.name, 1).replace('%s', node.computed_type.name, 1)) node.computed_type = ErrorType() return node.computed_type = node.expr.computed_type
def update(self, node, scope, ntype): if IsAuto(node.if_body.computed_type.name): self.update(node.if_body, scope, ntype) node.computed_type = node.if_body.computed_type if node.else_body: if IsAuto(node.else_body.computed_type.name): self.update(node.else_body, scope, ntype) names = [node.if_body.computed_type.name, node.else_body.computed_type.name] if 'AUTO_TYPE' not in names and '<error>' not in names: node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context) else: if '<error>' in names: node.computed_type = ErrorType() else: node.computed_type = self.context.get_type('AUTO_TYPE')
def visit(self, node, scope): self.visit(node.condition, scope) expr_type = node.condition.computed_type if not expr_type.name in ['Bool', 'AUTO_TYPE']: self.errors.append(CONDITION_NOT_BOOL.replace('%s', 'If', 1).replace('%s', expr_type.name, 1)) self.visit(node.if_body, scope) node.computed_type = node.if_body.computed_type if node.else_body: self.visit(node.else_body, scope) if IsAuto(node.if_body.computed_type.name) or IsAuto(node.else_body.computed_type.name): node.computed_type = self.context.get_type('AUTO_TYPE') elif '<error>' in [node.if_body.computed_type.name, node.else_body.computed_type.name]: node.computed_type = ErrorType() else: node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context)
def visit(self, node, scope): try: node_type = self.context.get_type(node.type) if node.type != 'SELF_TYPE' else self.current_type except SemanticError as ex: self.errors.append(ex.text) node_type = ErrorType() if not node.expr: node.computed_type = node_type return self.visit(node.expr, scope) expr_type = node.expr.computed_type if not (IsAuto(expr_type.name) or expr_type.conforms_to(node_type)): self.errors.append(INCOMPATIBLE_TYPES.replace('%s', expr_type.name, 1).replace('%s', node_type.name, 1)) node.computed_type = node_type
def visit(self, node, scope): self.visit(node.condition, scope) expr_type = node.condition.computed_type if IsAuto(expr_type.name): self.update(node.condition, scope, self.context.get_type('Bool')) expr_type = node.condition.computed_type if expr_type.name not in ['Bool', 'AUTO_TYPE']: self.errors.append(CONDITION_NOT_BOOL.replace('%s', 'If', 1).replace('%s', expr_type.name, 1)) self.visit(node.if_body, scope) node.computed_type = node.if_body.computed_type if node.else_body: self.visit(node.else_body, scope) names = [node.if_body.computed_type.name, node.else_body.computed_type.name] if 'AUTO_TYPE' not in names and '<error>' not in names: node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context) else: if '<error>' in names: node.computed_type = ErrorType() else: node.computed_type = self.context.get_type('AUTO_TYPE')
class InferenceVisitor(object): def __init__(self, context, errors=[]): self.context = context self.current_type = None self.current_method = None self.errors = errors @visitor.on('node') def update(self, node, scope, ntype): pass @visitor.when(Node) def update(self, node, scope, ntype): pass @visitor.when(FunctionCallNode) def update(self, node, scope, ntype): obj_type = node.obj.computed_type obj_type.get_method(node.id).return_type = ntype node.computed_type = ntype @visitor.when(MemberCallNode) def update(self, node, scope, ntype): obj_type = self.current_type obj_type.get_method(node.id).return_type = ntype node.computed_type = ntype @visitor.when(AttrDeclarationNode) def update(self, node, scope, ntype): scope.find_variable(node.id).type = ntype node.computed_type = ntype @visitor.when(IdNode) def update(self, node, scope, ntype): scope.find_variable(node.lex).type = ntype node.computed_type = ntype @visitor.when(IfThenElseNode) def update(self, node, scope, ntype): if IsAuto(node.if_body.computed_type.name): self.update(node.if_body, scope, ntype) node.computed_type = node.if_body.computed_type if node.else_body: if IsAuto(node.else_body.computed_type.name): self.update(node.else_body, scope, ntype) names = [node.if_body.computed_type.name, node.else_body.computed_type.name] if 'AUTO_TYPE' not in names and '<error>' not in names: node.computed_type = LCA([node.if_body.computed_type, node.else_body.computed_type], self.context) else: if '<error>' in names: node.computed_type = ErrorType() else: node.computed_type = self.context.get_type('AUTO_TYPE') @visitor.when(CaseOfNode) def update(self, node, scope, ntype): types_list = [] has_auto = has_error = False for case in node.branches: if IsAuto(case.computed_type.name): self.update(branch, scope, ntype) has_auto |= IsAuto(case.expr.computed_type.name) has_error |= case.expr.computed_type.name == '<error>' types_list.append(case.expr.computed_type) if has_error: node.computed_type = ErrorType() elif has_auto: node.computed_type = self.context.get_type('AUTO_TYPE') else: node.computed_type = LCA(types_list)