def visit(self, node): try: self.current_type = self.context.get_type(node.id, node.pos) except SemanticError as error: self.current_type = ErrorType() self.errors.append(error) if node.parent is not None: if node.parent in ['Int', 'String', 'Bool']: self.errors.append(SemanticError(INHERIT_ERROR % (node.id, node.parent), *node.parent_pos)) try: parent = self.context.get_type(node.parent, node.parent_pos) except SemanticError: self.errors.append(TypesError(INHERIT_UNDEFINED % (node.id, node.parent), *node.parent_pos)) parent = None try: current = parent while current is not None: if current.name == self.current_type.name: raise SemanticError(CIRCULAR_DEPENDENCY %(self.current_type.name, self.current_type.name) , *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, 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: self.errors.append( SemanticError( WRONG_SIGNATURE_RETURN % (node.id, method.return_type.name, old_meth.return_type.name), *node.type_pos)) if len(method.param_names) != len(old_meth.param_names): self.errors.append( SemanticError(WRONG_NUMBER_PARAM % node.id, *node.pos)) for (name, param), type1, type2 in zip(node.params, method.param_types, old_meth.param_types): if type1.name != type2.name: self.errors.append( SemanticError( WRONG_SIGNATURE_PARAMETER % (name, type1.name, type2.name), *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): self.errors.append( TypesError(RETURN_TYPE_ERROR % (result.name, return_type.name), *node.type_pos))
def visit(self, node, scope): cond = self.visit(node.cond, scope) if cond.name != 'Bool': self.errors.append( TypesError(PREDICATE_ERROR % ('if', 'Bool'), *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, scope): try: type_ = self.context.get_type(node.lex, node.pos) except SemanticError: type_ = ErrorType() self.errors.append( TypesError(NEW_UNDEFINED_CLASS % node.lex, *node.pos)) return get_type(type_, self.current_type)
def visit(self, node, 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): self.errors.append( TypesError(UNCONFORMS_TYPE % (typex.name, node.id, vtype.name), *node.pos)) return typex
def visit(self, node, scope): ltype = self.visit(node.expr, scope) int_type = IntType() if ltype != int_type: self.errors.append( TypesError( UOPERATION_NOT_DEFINED % ('~', ltype.name, int_type.name), *node.pos)) return ErrorType() return int_type
def visit(self, node, scope): ltype = self.visit(node.expr, scope) typex = BoolType() if ltype != typex: self.errors.append( TypesError( UOPERATION_NOT_DEFINED % ('not', ltype.name, typex.name), *node.pos)) return ErrorType() return typex
def visit(self, node, 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: self.errors.append(TypesError(COMPARISON_ERROR, *node.pos)) return ErrorType() else: return BoolType()
def visit(self, node, 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): self.errors.append( TypesError( UNCONFORMS_TYPE % (typex.name, node.id, vtype.name), *node.type_pos)) return typex return vtype
def visit(self, node:AttrDeclarationNode): try: attr_type = self.context.get_type(node.type, node.pos) except SemanticError as error: attr_type = ErrorType(node.type_pos) self.errors.append(TypesError(ATTR_TYPE_UNDEFINED %(node.type, node.id), *node.type_pos)) if node.id == 'self': self.errors.append(SemanticError(SELF_ATTR, *node.pos)) try: self.current_type.define_attribute(node.id, attr_type, node.pos) except SemanticError as error: self.errors.append(error)
def visit(self, node, 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): self.errors.append( TypesError( ATTR_TYPE_ERROR % (typex.name, attr.name, vartype.name), *node.pos)) return ErrorType() 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: self.errors.append( TypesError( BOPERATION_NOT_DEFINED % (ltype.name, operator, rtype.name), *node.pos)) return ErrorType() if operator == '<' or operator == '<=': return BoolType() return int_type
def visit(self, node, scope): obj = self.visit(node.obj, scope) typex = self.get_type(node.type, node.type_pos) if not obj.conforms_to(typex): self.errors.append( TypesError( INCOMPATIBLE_TYPES_DISPATCH % (typex.name, obj.name), *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:FuncDeclarationNode): args_names = [] args_types = [] for name, type_ in node.params: if name in args_names: self.errors.append(SemanticError(PARAMETER_MULTY_DEFINED % name, *type_.pos)) args_names.append(name) try: arg_type = self.context.get_type(type_.value, type_.pos) except SemanticError: self.errors.append(TypesError(PARAMETER_UNDEFINED % (type_.value, type_.value), *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 error: self.errors.append(TypesError(RETURN_TYPE_UNDEFINED % (node.type, node.id), *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 error: self.errors.append(error)
def _check_args(self, meth, scope, args, pos): arg_types = [self.visit(arg, scope) for arg in args] if len(arg_types) > len(meth.param_types): self.errors.append(SemanticError(ARGUMENT_ERROR % meth.name, *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):]): self.errors.append( SemanticError(ARGUMENT_ERROR % (meth.name), *arg_info.pos)) for atype, ptype, param_name in zip(arg_types, meth.param_types, meth.param_names): if not atype.conforms_to(ptype): self.errors.append( TypesError( INCOSISTENT_ARG_TYPE % (meth.name, atype.name, param_name, ptype.name), *pos))
def visit(self, node, scope): cond = self.visit(node.cond, scope) if cond.name != 'Bool': self.errors.append(TypesError(LOOP_CONDITION_ERROR, *node.pos)) self.visit(node.expr, scope) return ObjectType()