def VisitCastExpression(self, node): if not (isinstance(node.cast_type, PrimitiveType) or isinstance(node.cast_type, ClassOrInterfaceType) or isinstance(node.cast_type, NameExpression) or node.is_array): err(node[0].token, "A cast must be of primitive or reference types")
def Resolve(self, name): canon = name.AsString() resolved = self._ResolveCanon(canon, name) if resolved: name.linked_type = resolved else: err(name.tokens[0], "Resolver: Type does not exist: " + canon)
def VerifyReplaceDecl(old_decl, new_decl, abstract=False): old_header = old_decl.header new_header = new_decl.header old_modifiers = [x.lexeme for x in old_header.modifiers] new_modifiers = [x.lexeme for x in new_header.modifiers] m_name = new_header.m_id.lexeme # Check return types match if MakeTypeSig(old_header.m_type) != MakeTypeSig(new_header.m_type): err(new_header.m_id, "Return type mismatch in: " + m_name) # Check static -> non_static if 'static' in old_modifiers and 'static' not in new_modifiers: err(new_header.m_id, "Static replaced with non-static in: " + m_name) # Check nonstatic -> static if 'static' not in old_modifiers and 'static' in new_modifiers: err(new_header.m_id, "Non-static replaced with static in: " + m_name) # Check public -> protected if 'public' in old_modifiers and 'protected' in new_modifiers: err(new_header.m_id, "Public replaced with protected in: " + m_name) # Check override final if 'final' in old_modifiers: err(new_header.m_id, "Attempt to override final method: " + m_name)
def CheckInterfaceSimple(node): if node.extends_interface: CheckDuplicateInterfaces(node.name, node.extends_interface) for interface in node.extends_interface: if not isinstance(interface.linked_type, InterfaceDecl): err(node.name, "An interface must not extend a class: " + interface.AsString())
def VisitBlock(self, node): self.saw_return = False if node.stmts: for stmt in node.stmts: if self.saw_return or self.infinite_loop: err(node[0].token, "Unreachable statement.") self.Visit(stmt)
def VisitName(self, node): if not node.linked_type: if self.decl is not None: index = node.env.FieldIndex(node.Split()[0]) if index is not None and index >= self.decl: err(node.tokens[0], "Invalid forward reference: " + node.AsString()) self.linker.DisambiguateAndLink(node)
def ResolveLinkClassMethods(node): # Returns decls: set(MethodDecls) decl_map = collections.OrderedDict() class_modifiers = [x.lexeme for x in node.modifiers] is_abstract = 'abstract' in class_modifiers if node.interfaces: for interface in node.interfaces: decls = ResolveLinkInterfaceDecls(interface.linked_type) AddDecls(decls, decl_map) if node.extends: decls = ResolveLinkClassMethods(node.extends.linked_type) AddDecls(decls, decl_map, is_abstract) elif GetObject(): AddDecls(GetObject().method_decls, decl_map, is_abstract) if node is not GetObject(): AddDecls(node.method_decls, decl_map, is_abstract) if not is_abstract: for decl in decl_map.values(): if decl.IsAbstract(): err( node.name, "Non abstract class must implement all methods: " + decl.header.m_id.lexeme) node.method_map = decl_map return set(decl_map.values())
def VisitConstructorDecl(self, node): self._CheckModifiersCommon(node.name, node.modifiers) if node.name.lexeme != self.filename: err(node.name, "Constructor must have same name as base class") if node.body: node.body.visit(self)
def VisitWhileStatement(self, node): result = self.evaluator.Visit(node.test_expr) if result is False: err(node[0].token, "Unreachable statement in while loop.") if result is True: self.infinite_loop = True self.Visit(node.body) self.saw_return = False
def _ResolvePackageImports(self, canon, name): # Look in package imports results = name.env.LookupNameInPackages(canon) if results: if len(results) > 1: err(name.tokens[0], "Ambiguous usage of: " + canon) else: return results[0]
def _CheckPrefix(self, canon, name): split = canon.split('.') for i in range(1, len(split)): prefix = '.'.join(split[:i]) if self._ResolveCanon(prefix, name): err( name.tokens[0], "Prefix of qualified type should " "not resolve to a type: " + canon + ' prefix: ' + prefix)
def CheckConstructor(self, node): if node.linked_type.IsProtected(): own_pkg = node.env.LookupPackage() other_pkg = node.linked_type.env.LookupPackage() if own_pkg is None or other_pkg is None: if own_pkg != other_pkg: err(node[0].token, "Access of protected constructor") elif own_pkg[1] != other_pkg[1]: err(node[0].token, "Access of protected constructor")
def VisitMethodInvocation(self, node): if node.name: if self.decl is not None: index = node.env.FieldIndex(node.name.Split()[0]) if index is not None and index >= self.decl: err(node.name.tokens[0], "Invalid forward reference: " + node.name.AsString()) self.linker.DisambiguateAndLinkMethod(node) self.Visit(node.primary) self.Visit(node.args)
def VisitMethodDecl(self, node): should_ret = not isinstance(node.header.m_type, VoidType) self.infinite_loop = False self.saw_return = False if node.body_block: self.Visit(node.body_block) if not self.infinite_loop: if should_ret and not self.saw_return: err(node.header.m_id, "Expected return statement.")
def VisitFieldDecl(self, node): self._CheckModifiersCommon(node.var_decl.var_id, node.modifiers) modifiers = [x.lexeme for x in node.modifiers] if 'final' in modifiers and node.var_decl.exp is None: err(node.modifiers[0], "A final field must be initialized") if 'public' not in modifiers and 'protected' not in modifiers: err(node.f_type, "Package cannot have private field") if node.var_decl: node.var_decl.visit(self)
def CheckDuplicateMethods(method_decls): if method_decls is None: return sigs = set() for decl in method_decls: sig = tuple(MakeMethodSig(decl.header)) if sig in sigs: err(decl.header.m_id, "Duplicate method definition: " + decl.header.m_id.lexeme) sigs.add(sig)
def VisitMethodDecl(self, node): node.header.visit(self) modifiers = [x.lexeme for x in node.header.modifiers] if (('abstract' in modifiers or 'native' in modifiers) and node.body_block is not None): err(node.header.modifiers[0], "A method has a body if and" "only if it is neither abstract nor native") if node.body_block is not None and node.body_block.stmts is not None: for stmt in node.body_block.stmts: stmt.visit(self)
def VisitInterfaceDecl(self, node): if node.name.lexeme != self.filename: err(node.name, "The interface name must match the filename " + self.filename) if node.method_decls: for decl in node.method_decls: modifiers = [x.lexeme for x in decl.header.modifiers] if ('static' in modifiers or 'final' in modifiers or 'native' in modifiers): err(decl.header.modifiers[0], ('An interface method cannot be ' 'static, final, or native')) decl.header.visit(self)
def _CheckModifiersCommon(self, name, modifiers): # Check duplicate hashed = set() for modifier in modifiers: if modifier.lexeme in hashed: err(modifier, "Duplicate modifier: " + modifier.lexeme) hashed.add(modifier.lexeme) modifiers = [x.lexeme for x in modifiers] # Check no package private if ('public' not in modifiers and 'protected' not in modifiers and 'private' not in modifiers): err(name, "Cannot have package private modifiers")
def CheckLinkConstructors(node): if node.constructor_decls is None: return cons_map = {} for decl in node.constructor_decls: sig = tuple(MakeMethodSig(decl)) if sig in cons_map: err(decl.name, "Duplicate constructor definition: " + decl.name.lexeme) cons_map[sig] = decl node.cons_map = cons_map
def CheckAccess(self, debug_token, names, context): if not names: return context for current in names: try: if context.type == AccessContext.PKG: (type, decl, linked) = self.CheckInPackage(current, context) else: b = self.CheckAll(current, context) (type, decl, linked) = self.CheckAll(current, context) context = AccessContext(type, decl, context.parent_type, linked) except AccessError, e: err(debug_token, e.message)
def CheckClassNoCycles(node): if node in acyclic_class_nodes: return visited_set = set(node) while True: extends = node.extends if extends: node = extends.linked_type if node in visited_set: err(node.name, "Cyclic inheritance of: " + extends.AsString()) visited_set.add(node) else: break acyclic_class_nodes.add(node)
def CheckInterfaceNoCycles(node, path=None): if node in acyclic_interface_nodes: return if path is None: path = set() if node.extends_interface: path.add(node) for name in node.extends_interface: if name.linked_type in path: err(node.name, "Cyclic interface extends: " + name.AsString()) CheckInterfaceNoCycles(name.linked_type, path) path.remove(node) acyclic_interface_nodes.add(node)
def AddClassImport(self, node, decl): # node : Name name = node.Last() type = self.LookupClassOrInterface() if type is not None and name == type[0]: pkg = self.LookupPackage() decl = self.LookupClassOrInterface() if pkg and decl: pkg = pkg[0] decl = decl[0] # You are allowed to import yourself if not (node.Prefix() == pkg and node.Last() == decl): err(node.tokens[0], "Import clashes with class decl: " + name) class_import = self.LookupClassImport(name) if class_import is not None: class_name = class_import[0] # You can include the same thing twice if node.AsString() != class_name.AsString(): err(node.tokens[0], "Import clashes with another: " + name) self.class_imports[name] = (node, decl)
def VisitMethodHeader(self, node): self._CheckModifiersCommon(node.m_id, node.modifiers) modifiers = [x.lexeme for x in node.modifiers] if 'abstract' in modifiers and ('static' in modifiers or 'final' in modifiers): err(node.modifiers[0], 'An abstract method cannot be static or final') if 'static' in modifiers and 'final' in modifiers: err(node.modifiers[0], 'A static method cannot be final') if 'native' in modifiers and 'static' not in modifiers: err(node.modifiers[0], 'A native method must be static') if 'public' not in modifiers and 'protected' not in modifiers: err("Package cannot have private field")
def CheckMethodName(self, node, is_static): tokens = node.name.Split() parent = node.env.LookupClassOrInterface()[1] if is_static: context = AccessContext(AccessContext.CLASS, node, parent) else: context = AccessContext(AccessContext.EXPR, node, parent) context = self.CheckAccess(node[1].token, tokens[:-1], context) if (context.type == AccessContext.CLASS and not node.linked_method.IsStatic()): err(node[1].token, "Access of non-static method in static context") if (context.type == AccessContext.EXPR and node.linked_method.IsStatic()): err(node[1].token, "Access of static method in non-static context") if node.linked_method.IsStatic(): context.decl = node.linked_method.env.LookupClassOrInterface()[1] if node.linked_method.IsProtected(): if not self.CanAccessProtected( context, node.linked_method, static=node.linked_method.IsStatic()): err(node[1].token, "Access of protected method") node.context = context
def DisambiguateAndLink(self, node, name_tokens=None): tokens = name_tokens if not name_tokens: tokens = node.Split() first = tokens[0] env = node.env result = self.CheckNameAndEnv(first, env) if result: name_type, decl_or_pkg = result for name in tokens[1:]: if decl_or_pkg is None: err(node.tokens[0], "Name " + node.AsString() + " not found.") if name_type == NameType.PACKAGE: next = (self.CheckTypeInPackage(name, decl_or_pkg) or self.CheckPackageInPackage(name, decl_or_pkg)) elif name_type == NameType.TYPE or name_type == NameType.EXPR: if isinstance(decl_or_pkg, ArrayType): if name == 'length': next = (NameType.TYPE, ArrayType.LengthDecl) elif isinstance(decl_or_pkg, PrimitiveType): err(node.tokens[0], "Cannot dereference primitive type") else: next = (self.CheckFields(name, decl_or_pkg.env)) if not next: err(node.tokens[0], "Name " + node.AsString() + " not found.") name_type, decl_or_pkg = next if name_type == NameType.PACKAGE: err(node.tokens[0], "Unexpected package") node.name_type = name_type node.linked_type = decl_or_pkg else: err(node.tokens[0], "Name " + node.AsString() + " not found.")
def RecursiveAddNode(self, pkg_list, decl_tuple): (name, decl) = decl_tuple if pkg_list: first, last = pkg_list[0], pkg_list[1:] if first not in self.packages: if first in self.decls and self.packages: err(decl.name, 'Attempted to redefine type with package: ' + name) self.packages[first] = TypeMap() self.packages[first].RecursiveAddNode(last, decl_tuple) else: if name in self.decls: err(decl.name, "Duplicate definition of " + name) if name in self.packages and not self.default: err(decl.name, "Attempted to redefine package with type: " + name) self.decls[name] = decl
def CheckClassSimple(node): class_modifiers = [x.lexeme for x in node.modifiers] is_abstract = 'abstract' in class_modifiers if node.extends is not None: if not isinstance(node.extends.linked_type, ClassDecl): err(node.name, "A class must extend a class") else: modifiers = [x.lexeme for x in node.extends.linked_type.modifiers] if 'final' in modifiers: err(node.name, "A class must not extend a final class") if node.interfaces is not None: CheckDuplicateInterfaces(node.name, node.interfaces) for interface in node.interfaces: if not isinstance(interface.linked_type, InterfaceDecl): err(node.name, "A class must implement an interface.")
def CheckDuplicateInterfaces(name, nodes): decls = set() for interface in nodes: if interface.linked_type in decls: err(name, "Duplicate interface impl: " + interface.AsString()) decls.add(interface.linked_type)