diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 8e2091cc6b1..24e67766e3e 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -447,11 +447,21 @@ namespace MetaData { case Attribute::Virtual: case Attribute::Final: { - // XXX Here the spec. has ???, so the following is tentative FunctionInstance *fObj = validateStaticFunction(&f->function, compileThis, prototype, unchecked, cxt, env); JS2Class *c = checked_cast(env->getTopFrame()); Multiname *mn = new Multiname(f->function.name, a->namespaces); - InstanceMember *m = new InstanceMethod(mn, fObj, (memberMod == Attribute::Final), true); + InstanceMember *m; + switch (f->function.prefix) { + case FunctionName::normal: + m = new InstanceMethod(mn, fObj, (memberMod == Attribute::Final), true); + break; + case FunctionName::Set: + m = new InstanceSetter(mn, fObj, objectClass, (memberMod == Attribute::Final), true); + break; + case FunctionName::Get: + m = new InstanceGetter(mn, fObj, objectClass, (memberMod == Attribute::Final), true); + break; + } defineInstanceMember(c, cxt, f->function.name, a->namespaces, a->overrideMod, a->xplicit, m, p->pos); } break; @@ -639,6 +649,67 @@ namespace MetaData { break; case StmtNode::empty: break; + case StmtNode::Package: + { + PackageStmtNode *ps = checked_cast(p); + String packageName = getPackageName(ps->packageIdList); + Package *package = new Package(packageName, new Namespace(&world.identifiers["internal"])); + package->status = Package::InTransit; + packages.push_back(package); + env->addFrame(package); + ValidateStmt(cxt, env, pl, ps->body); + env->removeTopFrame(); + package->status = Package::InHand; + } + break; + case StmtNode::Import: + { + ImportStmtNode *i = checked_cast(p); + String packageName; + if (i->packageIdList) + packageName = getPackageName(i->packageIdList); + else + packageName = *i->packageString; + + if (!checkForPackage(packageName, i->pos)) + loadPackage(packageName, packageName + ".js"); + + Multiname mn(&packageName, publicNamespace); + js2val packageValue; + env->lexicalRead(this, &mn, CompilePhase, &packageValue, NULL); + if (JS2VAL_IS_VOID(packageValue) || JS2VAL_IS_NULL(packageValue) || !JS2VAL_IS_OBJECT(packageValue) + || (JS2VAL_TO_OBJECT(packageValue)->kind != PackageKind)) + reportError(Exception::badValueError, "Package expected in Import directive", i->pos); +#if 0 + + Package *package = checked_cast(JS2VAL_TO_OBJECT(packageValue)); + + if (i->varName) + // defineVariable(m_cx, *i->varName, NULL, Package_Type, JSValue::newPackage(package)); + + // scan all local bindings in 'package' and handle the alias-ing issue... + for (PropertyIterator it = package->mProperties.begin(), end = package->mProperties.end(); + (it != end); it++) + { + ASSERT(PROPERTY_KIND(it) == ValuePointer); + bool makeAlias = true; + if (i->includeExclude) { + makeAlias = i->exclude; + IdentifierList *idList = i->includeExclude; + while (idList) { + if (idList->name.compare(PROPERTY_NAME(it)) == 0) { + makeAlias = !makeAlias; + break; + } + idList = idList->next; + } + } + if (makeAlias) + defineAlias(m_cx, PROPERTY_NAME(it), PROPERTY_NAMESPACELIST(it), PROPERTY_ATTR(it), PROPERTY_TYPE(it), PROPERTY_VALUEPOINTER(it)); + } +#endif + } + break; default: NOT_REACHED("Not Yet Implemented"); } // switch (p->getKind()) @@ -649,6 +720,49 @@ namespace MetaData { } } + /* + Build a name for the package from the identifier list + */ + String JS2Metadata::getPackageName(IdentifierList *packageIdList) + { + String packagePath; + IdentifierList *idList = packageIdList; + while (idList) { + packagePath += idList->name; + idList = idList->next; + if (idList) + packagePath += '/'; // XXX how to get path separator for OS? + } + return packagePath; + } + + /* + See if the specified package is already loaded - return true + Throw an exception if the package is being loaded already + */ + bool JS2Metadata::checkForPackage(const String &packageName, size_t pos) + { + // XXX linear search + for (PackageList::iterator pi = packages.begin(), end = packages.end(); (pi != end); pi++) { + if ((*pi)->name.compare(packageName) == 0) { + if ((*pi)->status == Package::InTransit) + reportError(Exception::referenceError, "Package circularity", pos); + else + return true; + } + } + return false; + } + + /* + Load the specified package from the file + */ + void JS2Metadata::loadPackage(const String & /*packageName*/, const String &filename) + { + // XXX need some rules for search path + // XXX need to extract just the target package from the file + readEvalFile(filename); + } JS2Class *JS2Metadata::getVariableType(Variable *v, Phase phase, size_t pos) { @@ -3406,7 +3520,7 @@ bool nullClass_BracketDelete(JS2Metadata *meta, js2val base, JS2Class *limit, Mu engine(new JS2Engine(world)), publicNamespace(new Namespace(engine->public_StringAtom)), bCon(new BytecodeContainer()), - glob(new Package(new Namespace(&world.identifiers["internal"]))), + glob(new Package(widenCString("global"), new Namespace(&world.identifiers["internal"]))), env(new Environment(new MetaData::SystemFrame(), glob)), flags(JS1), showTrees(false), @@ -4409,7 +4523,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... JS2Object *obj = new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass); DEFINE_ROOTKEEPER(rk2, obj); - meta->createDynamicProperty(this, meta->engine->prototype_StringAtom, OBJECT_TO_JS2VAL(obj), ReadWriteAccess, false, true); + meta->createDynamicProperty(this, meta->engine->prototype_StringAtom, OBJECT_TO_JS2VAL(obj), ReadWriteAccess, true, false); } diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 723728939bc..7a79a22c399 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -559,9 +559,9 @@ public: class InstanceGetter : public InstanceMember { public: - InstanceGetter(Multiname *multiname, Invokable *code, JS2Class *type, bool final, bool enumerable) - : InstanceMember(InstanceGetterMember, multiname, final, enumerable), code(code), type(type) { } - Invokable *code; // A callable object which does the read or write; null if this method is abstract + InstanceGetter(Multiname *multiname, FunctionInstance *fInst, JS2Class *type, bool final, bool enumerable) + : InstanceMember(InstanceGetterMember, multiname, final, enumerable), fInst(fInst), type(type) { } + FunctionInstance *fInst; // A callable object which does the read or write; null if this method is abstract JS2Class *type; // Type of values that may be stored in this variable virtual Access instanceMemberAccess() { return ReadAccess; } @@ -569,9 +569,9 @@ public: class InstanceSetter : public InstanceMember { public: - InstanceSetter(Multiname *multiname, Invokable *code, JS2Class *type, bool final, bool enumerable) - : InstanceMember(InstanceSetterMember, multiname, final, enumerable), code(code), type(type) { } - Invokable *code; // A callable object which does the read or write; null if this method is abstract + InstanceSetter(Multiname *multiname, FunctionInstance *fInst, JS2Class *type, bool final, bool enumerable) + : InstanceMember(InstanceSetterMember, multiname, final, enumerable), fInst(fInst), type(type) { } + FunctionInstance *fInst; // A callable object which does the read or write; null if this method is abstract JS2Class *type; // Type of values that may be stored in this variable virtual Access instanceMemberAccess() { return WriteAccess; } @@ -772,10 +772,15 @@ public: class Package : public NonWithFrame { public: - Package(Namespace *internal) : NonWithFrame(PackageKind), super(JS2VAL_VOID), sealed(false), internalNamespace(internal) { } + typedef enum { InTransit, InHand } PackageStatus; + + Package(const String &name, Namespace *internal) : NonWithFrame(PackageKind), super(JS2VAL_VOID), sealed(false), internalNamespace(internal), name(name) { } js2val super; bool sealed; Namespace *internalNamespace; // This Package's internal namespace + PackageStatus status; + String name; + virtual void markChildren(); virtual ~Package() { } }; @@ -1458,7 +1463,14 @@ public: bool showTrees; // debug only, causes parse tree dump - Arena *referenceArena; + Arena *referenceArena; // allocation arena for all reference objects + + typedef std::vector PackageList; + PackageList packages; // the currently loaded packages, packages.back() is the current package + + bool checkForPackage(const String &packageName, size_t pos); // return true if loaded, throw exception if loading + void loadPackage(const String &packageName, const String &filename); // load package from file + String getPackageName(IdentifierList *packageIdList); };