/* Static analysis, phase 1: build the package environment. Also resolve array allocation ambiguity and rewrite AllocateArrayNodes to eliminate EmptyArrayNodes, ExpressionArrayNodes and TitaniumArrayNodes */ #include "AST.h" #include "code-util.h" #include "compiler.h" #include "decls.h" #include "errors.h" #include "templates/Instantiations.h" #include "utils.h" void TreeNode::resolvePackage(Decl*, Environ *) { undefined("resolvePackage"); } void CompileUnitNode::resolvePackage(Decl *, Environ *) { foriter (type, types()->allChildren(), ChildIter) (*type)->resolvePackage (thePackage, environ()); // Must do this after the types, because we want to build this files environment // before we start loading the imported types foriter (import, imports()->allChildren(), ChildIter) (*import)->resolveImports(this, environ()); } void ClassDeclNode::resolvePackage(Decl *package, Environ *fileEnv) { Decl *other = fileEnv->lookupProper(simpName()->ident()); if (other) { error() << "attempt to redefine " << other->errorName() << " as a class" << endl; return; } Environ *packageEnv = fileEnv->parent(); other = packageEnv->lookupProper(simpName()->ident()); if (other && (!other->source() || other->source()->absent())) { // Assume this is the definition of 'other' other->source(this); other->modifiers(flags()); } else { ClassDecl *cl = new ClassDecl(simpName()->ident(), package, flags(), this); if (other) // Redefinition in same package. error() << "class name " << *simpName()->ident() << " conflicts with " << other->errorName() << " in same package" << endl; else packageEnv->add(cl); other = cl; } other->environ(new Environ(fileEnv)); fileEnv->add(other); simpName()->decl(other); } void InterfaceDeclNode::resolvePackage(Decl *package, Environ *fileEnv) { Decl *other = fileEnv->lookupProper(simpName()->ident()); if (other) { error() << "attempt to redefine " << other->errorName() << " as an interface" << endl; return; } Environ *packageEnv = fileEnv->parent(); other = packageEnv->lookupProper(simpName()->ident()); if (other && (!other->source() || other->source()->absent())) { // Assume this is the definition of 'other' other->source(this); other->modifiers((Common::Modifiers)(Common::Interface | flags())); } else { ClassDecl *cl = new ClassDecl(simpName()->ident(), package, (Common::Modifiers) (Common::Interface | flags()), this); if (other) // Redefinition in same package. error() << "interface name " << *simpName()->ident() << " conflicts with " << other->errorName() << " in same package" << endl; else packageEnv->add(cl); other = cl; } other->environ(new Environ(fileEnv)); fileEnv->add(other); simpName()->decl(other); } void TemplateDeclNode::resolvePackage( Decl *package, Environ *fileEnv ) { basis()->resolvePackage( package, fileEnv ); decl()->instantiations = new Instantiations; } //////////////////////////////////////////////////////////////////////// void TreeNode::resolveImports(CompileUnitNode *, Environ *) { undefined("resolveImports"); } void ImportNode::resolveImports(CompileUnitNode *, Environ *fileEnv) { int errs0 = NumErrors(); resolveAName(name(), *(PackageDecl::System->environ()), NULL, None, NULL, Decl::Class | Decl::Interface); if (errs0 == NumErrors()) { Decl *old = fileEnv->lookupProper(name()->ident()); if (old != NULL && old != name()->decl()) { if (old != name()->decl()) error() << "attempt to import conflicting name: " << old->errorName() << endl; } else fileEnv->add(name()->decl()); } } void ImportOnDemandNode::resolveImports(CompileUnitNode *file, Environ *) { int errs0 = NumErrors(); resolveAName(name(), *(PackageDecl::System->environ()), NULL, None, NULL, Decl::Package); if (errs0 == NumErrors()) file->importOnDemand(name()->decl()); } void CompileUnitNode::importOnDemand(Decl *importedPackage) { // ignore duplicate imports if (find(importedPackage, importedPackages)) return; importedPackages = cons(importedPackage, importedPackages); Environ* env = environ()->parent()->parent(); foriter (type, importedPackage->environ()->allProperDecls(), EnvironIter) if (type->category() != Decl::Package) env->add(&*type); // conflicts appear on use only } void CompileUnitNode::importOnDemand(const string *s1, const string *s2) { NameNode outer( TreeNode::omitted, s1, NULL ); NameNode name( &outer, s2, NULL ); int errs0 = NumErrors(); resolveAName(&name, *(PackageDecl::System->environ()), NULL, None, NULL, Decl::Package); if (errs0 == NumErrors()) importOnDemand(name.decl()); } // Load all the explicitly visible types (more might appear when we // start resolving names, but we don't need those to build the class-level // environment TreeNode *TreeNode::resolveTypes(Decl *package, Environ *fileEnv, Environ *typeEnv) { const int count = arity(); for (int sweep = 0; sweep < count; ++sweep) child( sweep, child( sweep )->resolveTypes( package, fileEnv, typeEnv ) ); return this; } TreeNode *TypeNameNode::resolveTypes(Decl *package, Environ *fileEnv, Environ *typeEnv) { TreeNode * const myName = name(); TreeNode * const resolved = resolveAName(myName, *typeEnv, NULL, None, package, Decl::Class | Decl::Interface | Decl::TypePseudonym); if (myName->decl()->category() & Decl::TypePseudonym) { assert( resolved->isTypeNode() ); TypeNode &referent = static_cast< TypeNode & >( *resolved ); return referent.addModifiers( modifiers() ); // : should we be checking that the modifiers actually make sense? // : for example, what do we do with "int local" ? } else { assert( resolved == name() ); return this; } } TreeNode *AllocateArrayNode::resolveTypes(Decl *package, Environ *fileEnv, Environ *typeEnv) { /* Finish parsing (due to ambiguity in new X[3][(n)d] whose meaning depends on whether n is a type */ TypeNode *dt = dtype(); llist *dims = NULL; bool exprOnly = false; for (int i = dimExprs()->arity(); i > 0; ) exprOnly = dimExprs()->child(--i)->resolveNewArray(package, fileEnv, exprOnly, &dims, &dt); if (!dims) error() << "No array size specified" << endl; dimExprs(new TreeListNode(dims)); dtype(dt); return TreeNode::resolveTypes(package, fileEnv, typeEnv); } bool TreeNode::resolveNewArray(Decl *, Environ *, bool, llist **, TypeNode **) { unimplemented("resolveNewArray"); return false; } bool AllocateArrayDimensionNode::resolveNewArray(Decl *, Environ *, bool exprOnly, llist **dims, TypeNode **base) { *dims = cons((TreeNode *)this, *dims); return true; } static bool arrayTypeSpecifier(TreeNode *x, bool exprOnly, TypeNode **base) { if (exprOnly) x->error() << "new: array type specifier followed by expression" << endl; *base = x->asType2(*base); return false; } bool EmptyArrayNode::resolveNewArray(Decl *, Environ *, bool exprOnly, llist **dims, TypeNode **base) { return arrayTypeSpecifier(this, exprOnly, base); } bool TitaniumArrayNode::resolveNewArray(Decl *, Environ *, bool exprOnly, llist **dims, TypeNode **base) { return arrayTypeSpecifier(this, exprOnly, base); } bool ExpressionArrayNode::resolveNewArray(Decl *package, Environ *fileEnv, bool exprOnly, llist **dims, TypeNode **base) { if (expr()->args()->arity() != 1) { error() << "Unexpected expression list" << endl; return true; } else if (expr()->isArraySpecifier(package, fileEnv)) // We get some redundant computation here, but makes life simpler return arrayTypeSpecifier(this, exprOnly, base); else { *dims = cons((TreeNode *)(new AllocateArrayDimensionNode(expr()->args()->child(0), flags())), *dims); return true; } } bool TreeNode::isArraySpecifier(Decl *, Environ *) { return false; } bool PointNode::isArraySpecifier(Decl *package, Environ *fileEnv) { if (args()->arity() != 1) return false; else return args()->child(0)->isArraySpecifier(package, fileEnv); } bool PrimitiveLitNode::isArraySpecifier(Decl *, Environ *) { return literal().isNd(); } bool CastNode::isArraySpecifier(Decl *package, Environ *fileEnv) { TypeNode *dt = dtype(); if (opnd0()->isd() && dt->isNamedType() && !dt->modifiers()) { EnvironIter typeMatches = qualifiedLookup(dt->name(), *fileEnv, NULL, None, package, Decl::Class | Decl::Interface); /* We assume it was (Expr) d if there are no matches for the type */ if (typeMatches.isDone()) return true; } return false; } TreeNode *CompileUnitNode::resolveTypes(Decl *, Environ *, Environ *) { types()->resolveTypes( thePackage, environ(), environ() ); return this; } TreeNode *TemplateDeclNode::resolveTypes( Decl *package, Environ *fileEnv, Environ *typeEnv ) { // : should each formal be in scope while resolving subsequent formals? params()->resolveTypes( package, fileEnv, typeEnv ); return this; } TreeNode *TemplateInstanceDeclNode::resolveTypes( Decl *package, Environ *fileEnv, Environ * ) { return TreeNode::resolveTypes( package, fileEnv, environ() ); } TreeNode *TemplateInstanceTypeNode::resolveTypes( Decl *package, Environ *fileEnv, Environ *typeEnv ) { TypeNameNode &type = static_cast< TypeNameNode & >( *dtype() ); assert( isTypeNameNode( &type ) ); // figure out what template we are using type.resolveTypes( package, fileEnv, typeEnv ); // template name may be used as a template within its own definition const ClassDecl &basis = *type.decl(); if (basis.templateBasis) type.name()->decl( basis.templateBasis ); // perform basic sanity checking; if everything looks sane, then // disambiguate actuals with respect to the underlying template decl( checkTemplateUse() ); // finish up type resolution for actuals args()->resolveTypes( package, fileEnv, typeEnv ); return this; } void TreeNode::packageResolution() { undefined("packageResolution"); } void CompileUnitNode::packageResolution() { if (package()->absent()) thePackage = unnamedPackage; else thePackage = resolveAName(package(), *PackageDecl::System->environ(), NULL, None, NULL, Decl::Package)->decl(); // build environment for this file Environ *importOnDemandEnv = new Environ(PackageDecl::System->environ()); Environ *packageEnv = new Environ(importOnDemandEnv); environ(new Environ(packageEnv)); // the file level environment packageEnv->copy(thePackage->environ()); importOnDemand(JavaString, LangString); importOnDemand(TitaniumString, LangString); resolvePackage(NULL, NULL); resolveTypes(NULL, NULL, NULL); }