def visit(self, node: FuncDeclarationNode): args_names = [] args_types = [] for name, type_ in node.params: if name in args_names: error_text = SemanticError.PARAMETER_MULTY_DEFINED % name self.errors.append(SemanticError(error_text, *type_.pos)) args_names.append(name) try: arg_type = self.context.get_type(type_.value, type_.pos) except SemanticError: error_text = TypesError.PARAMETER_UNDEFINED % (type_.value, type_.value) self.errors.append(TypesError(error_text, *type_.pos)) arg_type = ErrorType() args_types.append(arg_type) try: return_type = self.context.get_type(node.type, node.type_pos) except SemanticError as e: error_text = TypesError.RETURN_TYPE_UNDEFINED % (node.type, node.id) self.errors.append(TypesError(error_text, *node.type_pos)) return_type = ErrorType(node.type_pos) try: self.current_type.define_method(node.id, args_names, args_types, return_type, node.pos) except SemanticError as e: self.errors.append(e)
def visit(self, node: ClassDeclarationNode): try: self.current_type = self.context.get_type(node.id, node.pos) except SemanticError as e: self.current_type = ErrorType() self.errors.append(e) if node.parent is not None: if node.parent in ['Int', 'Bool', 'String']: error_text = SemanticError.INHERIT_ERROR % (node.id, node.parent) self.errors.append(SemanticError(error_text, *node.parent_pos)) try: parent = self.context.get_type(node.parent, node.parent_pos) except SemanticError: error_text = TypesError.INHERIT_UNDEFINED % (node.id, node.parent) self.errors.append(TypesError(error_text, *node.parent_pos)) parent = None try: current = parent while current is not None: if current.name == self.current_type.name: error_text = SemanticError.CIRCULAR_DEPENDENCY % ( self.current_type.name, self.current_type.name) raise SemanticError(error_text, *node.pos) current = current.parent except SemanticError as e: parent = ErrorType() self.errors.append(e) self.current_type.set_parent(parent) for feature in node.features: self.visit(feature)
def visit(self, node: InstantiateNode, scope: Scope): try: type_ = self.context.get_type(node.lex, node.pos) except SemanticError: type_ = ErrorType() error_text = TypesError.NEW_UNDEFINED_CLASS % node.lex self.errors.append(TypesError(error_text, *node.pos)) return get_type(type_, self.current_type)
def visit(self, node: NotNode, scope: Scope): ltype = self.visit(node.expr, scope) typex = BoolType() if ltype != typex: error_text = TypesError.UOPERATION_NOT_DEFINED % ( 'not', ltype.name, typex.name) self.errors.append(TypesError(error_text, *node.pos)) return ErrorType() return typex
def visit(self, node: BinaryNotNode, scope: Scope): ltype = self.visit(node.expr, scope) int_type = IntType() if ltype != int_type: error_text = TypesError.UOPERATION_NOT_DEFINED % ('~', ltype.name, int_type.name) self.errors.append(TypesError(error_text, *node.pos)) return ErrorType() return int_type
def visit(self, node: WhileNode, scope: Scope): cond = self.visit(node.cond, scope) if cond.name != 'Bool': self.errors.append( TypesError(TypesError.LOOP_CONDITION_ERROR, *node.pos)) self.visit(node.expr, scope) return ObjectType()
def visit(self, node: EqualNode, scope: Scope): ltype = self.visit(node.left, scope) rtype = self.visit(node.right, scope) if (ltype == IntType() or rtype == IntType() or ltype == StringType() or rtype == StringType() or ltype == BoolType() or rtype == BoolType()) and ltype != rtype: error_text = TypesError.COMPARISON_ERROR self.errors.append(TypesError(error_text, *node.pos)) return ErrorType() else: return BoolType()
def visit(self, node: ConditionalNode, scope: Scope): cond = self.visit(node.cond, scope) if cond.name != 'Bool': error_text = TypesError.PREDICATE_ERROR % ('if', 'Bool') self.errors.append(TypesError(error_text, *node.pos)) true_type = self.visit(node.stm, scope) false_type = self.visit(node.else_stm, scope) return get_common_basetype([false_type, true_type])
def visit(self, node: AssignNode, scope: Scope): vinfo = self.find_variable(scope, node.id) vtype = get_type(vinfo.type, self.current_type) typex = self.visit(node.expr, scope) if not typex.conforms_to(vtype): error_text = TypesError.UNCONFORMS_TYPE % (typex.name, node.id, vtype.name) self.errors.append(TypesError(error_text, *node.pos)) return typex
def binary_operation(self, node, scope, operator): ltype = self.visit(node.left, scope) rtype = self.visit(node.right, scope) int_type = IntType() if ltype != int_type or rtype != int_type: error_text = TypesError.BOPERATION_NOT_DEFINED % ( ltype.name, operator, rtype.name) self.errors.append(TypesError(error_text, *node.pos)) return ErrorType() if operator == '<' or operator == '<=': return BoolType() return int_type
def visit(self, node: VarDeclarationNode, scope: Scope): vtype = self._get_type(node.type, node.type_pos) vtype = get_type(vtype, self.current_type) if node.expr != None: typex = self.visit(node.expr, scope) if not typex.conforms_to(vtype): error_text = TypesError.UNCONFORMS_TYPE % (typex.name, node.id, vtype.name) self.errors.append(TypesError(error_text, *node.type_pos)) return typex return vtype
def visit(self, node: AttrDeclarationNode, scope: Scope): attr = self.current_type.get_attribute(node.id, node.pos) vartype = get_type(attr.type, self.current_type) self.current_index = attr.index typex = self.visit(node.expr, scope) self.current_index = None if not typex.conforms_to(vartype): error_text = TypesError.ATTR_TYPE_ERROR % (typex.name, attr.name, vartype.name) self.errors.append(TypesError(error_text, *node.pos)) return ErrorType() return typex
def visit(self, node: BaseCallNode, scope: Scope): obj = self.visit(node.obj, scope) typex = self._get_type(node.type, node.type_pos) if not obj.conforms_to(typex): error_text = TypesError.INCOMPATIBLE_TYPES_DISPATCH % (typex.name, obj.name) self.errors.append(TypesError(error_text, *node.type_pos)) return ErrorType() meth = self._get_method(typex, node.id, node.pos) if not isinstance(meth, MethodError): self._check_args(meth, scope, node.args, node.pos) return get_type(meth.return_type, typex)
def visit(self, node: AttrDeclarationNode): try: attr_type = self.context.get_type(node.type, node.pos) except SemanticError as e: error_text = TypesError.ATTR_TYPE_UNDEFINED % (node.type, node.id) attr_type = ErrorType(node.type_pos) self.errors.append(TypesError(error_text, *node.type_pos)) if node.id == 'self': self.errors.append( SemanticError(SemanticError.SELF_ATTR, *node.pos)) try: self.current_type.define_attribute(node.id, attr_type, node.pos) except SemanticError as e: self.errors.append(e)
def _check_args(self, meth: Method, scope: Scope, args, pos): arg_types = [self.visit(arg, scope) for arg in args] if len(arg_types) > len(meth.param_types): error_text = SemanticError.ARGUMENT_ERROR % meth.name self.errors.append(SemanticError(error_text, *pos)) elif len(arg_types) < len(meth.param_types): for arg, arg_info in zip(meth.param_names[len(arg_types):], args[len(arg_types):]): error_text = SemanticError.ARGUMENT_ERROR % (meth.name) self.errors.append(SemanticError(error_text, *arg_info.pos)) for atype, ptype, param_name in zip(arg_types, meth.param_types, meth.param_names): if not atype.conforms_to(ptype): error_text = TypesError.INCOSISTENT_ARG_TYPE % ( meth.name, atype.name, param_name, ptype.name) self.errors.append(TypesError(error_text, *pos))
def visit(self, node: FuncDeclarationNode, scope: Scope): parent = self.current_type.parent self.current_method = method = self.current_type.get_method( node.id, node.pos) if parent is not None: try: old_meth = parent.get_method(node.id, node.pos) if old_meth.return_type.name != method.return_type.name: error_text = SemanticError.WRONG_SIGNATURE_RETURN % ( node.id, method.return_type.name, old_meth.return_type.name) self.errors.append( SemanticError(error_text, *node.type_pos)) if len(method.param_names) != len(old_meth.param_names): error_text = SemanticError.WRONG_NUMBER_PARAM % node.id self.errors.append(SemanticError(error_text, *node.pos)) for (name, param), type1, type2 in zip(node.params, method.param_types, old_meth.param_types): if type1.name != type2.name: error_text = SemanticError.WRONG_SIGNATURE_PARAMETER % ( name, type1.name, type2.name) self.errors.append( SemanticError(error_text, *param.pos)) except SemanticError: pass result = self.visit(node.body, scope) return_type = get_type(method.return_type, self.current_type) if not result.conforms_to(return_type): error_text = TypesError.RETURN_TYPE_ERROR % (result.name, return_type.name) self.errors.append(TypesError(error_text, *node.type_pos))
def get_type(self, name: str, pos) -> Type: try: return self.types[name] except KeyError: error_text = TypesError.TYPE_NOT_DEFINED % name raise TypesError(error_text, *pos)
def set_parent(self, parent): if type(self.parent) != ObjectType and self.parent is not None: error_text = TypesError.PARENT_ALREADY_DEFINED % self.name raise TypesError(error_text, *self.pos) self.parent = parent