diff --git a/js2/src/epimetheus.cpp b/js2/src/epimetheus.cpp index 48bb06f23353..b182ff258a91 100644 --- a/js2/src/epimetheus.cpp +++ b/js2/src/epimetheus.cpp @@ -237,7 +237,7 @@ void printFrameBindings(Frame *f) { stdOut << " Static Bindings:\n"; for (StaticBindingIterator rsb = f->staticReadBindings.begin(), rsend = f->staticReadBindings.end(); (rsb != rsend); rsb++) { - stdOut << "\t" << *rsb->second->qname.nameSpace->name << "::" << rsb->second->qname.id; + stdOut << "\t" << *rsb->second->qname.nameSpace->name << "::" << *rsb->second->qname.id; bool found = false; for (StaticBindingIterator wsb = f->staticWriteBindings.begin(), wsend = f->staticWriteBindings.end(); (wsb != wsend); wsb++) { if (rsb->second->qname == wsb->second->qname) { @@ -256,7 +256,7 @@ void printFrameBindings(Frame *f) } } if (!found) - stdOut << "\t" << *wsb->second->qname.nameSpace->name << "::" << wsb->second->qname.id << " [write-only]" << "\n"; + stdOut << "\t" << *wsb->second->qname.nameSpace->name << "::" << *wsb->second->qname.id << " [write-only]" << "\n"; } } @@ -289,7 +289,7 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint stdOut << " Instance Bindings:\n"; for (InstanceBindingIterator rib = c->instanceReadBindings.begin(), riend = c->instanceReadBindings.end(); (rib != riend); rib++) { - stdOut << "\t" << *rib->second->qname.nameSpace->name << "::" << rib->second->qname.id; + stdOut << "\t" << *rib->second->qname.nameSpace->name << "::" << *rib->second->qname.id; bool found = false; for (InstanceBindingIterator wib = c->instanceWriteBindings.begin(), wiend = c->instanceWriteBindings.end(); (wib != wiend); wib++) { if (rib->second->qname == wib->second->qname) { @@ -308,7 +308,7 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint } } if (!found) - stdOut << "\t" << *wib->second->qname.nameSpace->name << "::" << wib->second->qname.id << " [write-only]" << "\n"; + stdOut << "\t" << *wib->second->qname.nameSpace->name << "::" << *wib->second->qname.id << " [write-only]" << "\n"; } } else { diff --git a/js2/src/js2boolean.cpp b/js2/src/js2boolean.cpp index 639dfe02e936..e0c68e6f1115 100644 --- a/js2/src/js2boolean.cpp +++ b/js2/src/js2boolean.cpp @@ -67,6 +67,14 @@ namespace MetaData { return thatValue; } + static js2val Boolean_Call(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc) + { + if (argc > 0) + return BOOLEAN_TO_JS2VAL(meta->toBoolean(argv[0])); + else + return JS2VAL_FALSE; + } + static js2val Boolean_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) { if (meta->objectType(thisValue) != meta->booleanClass) @@ -75,9 +83,18 @@ namespace MetaData { return (boolInst->mValue) ? meta->engine->allocString(meta->engine->true_StringAtom) : meta->engine->allocString(meta->engine->false_StringAtom); } + static js2val Boolean_valueOf(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) + { + if (meta->objectType(thisValue) != meta->booleanClass) + meta->reportError(Exception::typeError, "Boolean.valueOf called on something other than a boolean thing", meta->engine->errorPos()); + BooleanInstance *boolInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); + return (boolInst->mValue) ? JS2VAL_TRUE : JS2VAL_FALSE; + } + void initBooleanObject(JS2Metadata *meta) { meta->booleanClass->construct = Boolean_Constructor; + meta->booleanClass->call = Boolean_Call; typedef struct { char *name; @@ -87,8 +104,8 @@ namespace MetaData { PrototypeFunction prototypeFunctions[] = { - { "toString", 0, Boolean_toString }, -// { "valueOf", 0, Boolean_valueOf }, + { "toString", 0, Boolean_toString }, + { "valueOf", 0, Boolean_valueOf }, { NULL } }; @@ -96,13 +113,20 @@ namespace MetaData { NamespaceList publicNamespaceList; publicNamespaceList.push_back(meta->publicNamespace); + meta->booleanClass->prototype = new PrototypeInstance(meta->objectClass->prototype, meta->booleanClass); + + meta->env->addFrame(meta->booleanClass); + Variable *v = new Variable(meta->booleanClass, OBJECT_TO_JS2VAL(meta->booleanClass->prototype), true); + meta->defineStaticMember(meta->env, meta->engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0); + meta->env->removeTopFrame(); + PrototypeFunction *pf = &prototypeFunctions[0]; while (pf->name) { CallableInstance *fInst = new CallableInstance(meta->functionClass); fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code); /* - XXX not prototype object function properties, like ECMA3, but members of the Date class - meta->writeDynamicProperty(meta->dateClass->prototype, new Multiname(meta->world.identifiers[pf->name], meta->publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase); + XXX not prototype object function properties, like ECMA3 + meta->writeDynamicProperty(meta->booleanClass->prototype, new Multiname(meta->world.identifiers[pf->name], meta->publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase); */ /* XXX not static members, since those can't be accessed from the instance diff --git a/js2/src/js2date.cpp b/js2/src/js2date.cpp index 267b567af139..34f6a602817a 100644 --- a/js2/src/js2date.cpp +++ b/js2/src/js2date.cpp @@ -1472,7 +1472,7 @@ void initDateObject(JS2Metadata *meta) CallableInstance *fInst = new CallableInstance(meta->functionClass); fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code); /* -XXX not prototype object function properties, like ECMA3, but members of the Date class +XXX not prototype object function properties, like ECMA3 meta->writeDynamicProperty(meta->dateClass->prototype, new Multiname(meta->world.identifiers[pf->name], meta->publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase); */ /* diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp index 3cac55cfa13a..7dcc1d7c0f20 100644 --- a/js2/src/js2metadata.cpp +++ b/js2/src/js2metadata.cpp @@ -2600,7 +2600,7 @@ doUnary: // - If the binding exists (not forbidden) in lower frames in the regional environment, it's an error. // - Define a forbidden binding in all the lower frames. // - Multiname *JS2Metadata::defineStaticMember(Environment *env, const StringAtom *id, NamespaceList *namespaces, + Multiname *JS2Metadata::defineStaticMember(Environment *env, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m, size_t pos) { @@ -2671,7 +2671,7 @@ doUnary: // Now insert the id, via all it's namespaces into the local frame for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) { - QualifiedName qName(*nli, *id); + QualifiedName qName(*nli, id); StaticBinding *sb = new StaticBinding(qName, m); const StaticBindingMap::value_type e(*id, sb); if (access & ReadAccess) @@ -2690,7 +2690,7 @@ doUnary: Frame *fr = *++fi; while (true) { for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) { - QualifiedName qName(*nli, *id); + QualifiedName qName(*nli, id); StaticBinding *sb = new StaticBinding(qName, forbiddenMember); const StaticBindingMap::value_type e(*id, sb); if (access & ReadAccess) @@ -2715,15 +2715,15 @@ doUnary: JS2Class *s = c; while (s) { if (access & ReadAccess) { - for (InstanceBindingIterator b = s->instanceReadBindings.lower_bound(qname->id), - end = s->instanceReadBindings.upper_bound(qname->id); (b != end); b++) { + for (InstanceBindingIterator b = s->instanceReadBindings.lower_bound(*qname->id), + end = s->instanceReadBindings.upper_bound(*qname->id); (b != end); b++) { if (*qname == b->second->qname) return b->second->content; } } if (access & WriteAccess) { - for (InstanceBindingIterator b = s->instanceWriteBindings.lower_bound(qname->id), - end = s->instanceWriteBindings.upper_bound(qname->id); (b != end); b++) { + for (InstanceBindingIterator b = s->instanceWriteBindings.lower_bound(*qname->id), + end = s->instanceWriteBindings.upper_bound(*qname->id); (b != end); b++) { if (*qname == b->second->qname) return b->second->content; } @@ -2739,7 +2739,7 @@ doUnary: { OverrideStatus *os = new OverrideStatus(NULL, id); for (NamespaceListIterator ns = namespaces->begin(), end = namespaces->end(); (ns != end); ns++) { - QualifiedName qname(*ns, *id); + QualifiedName qname(*ns, id); InstanceMember *m = findInstanceMember(c, &qname, access); if (m) { os->multiname.addNamespace(*ns); @@ -2789,7 +2789,7 @@ doUnary: } // For all the discovered possible overrides, make sure the member doesn't already exist in the class for (NamespaceListIterator nli = os->multiname.nsList.begin(), nlend = os->multiname.nsList.end(); (nli != nlend); nli++) { - QualifiedName qname(*nli, *id); + QualifiedName qname(*nli, id); if (access & ReadAccess) { for (InstanceBindingIterator b = c->instanceReadBindings.lower_bound(*id), end = c->instanceReadBindings.upper_bound(*id); (b != end); b++) { @@ -2851,14 +2851,14 @@ doUnary: NamespaceListIterator nli, nlend; for (nli = readStatus->multiname.nsList.begin(), nlend = readStatus->multiname.nsList.end(); (nli != nlend); nli++) { - QualifiedName qName(*nli, *id); + QualifiedName qName(*nli, id); InstanceBinding *ib = new InstanceBinding(qName, m); const InstanceBindingMap::value_type e(*id, ib); c->instanceReadBindings.insert(e); } for (nli = writeStatus->multiname.nsList.begin(), nlend = writeStatus->multiname.nsList.end(); (nli != nlend); nli++) { - QualifiedName qName(*nli, *id); + QualifiedName qName(*nli, id); InstanceBinding *ib = new InstanceBinding(qName, m); const InstanceBindingMap::value_type e(*id, ib); c->instanceWriteBindings.insert(e); @@ -2880,7 +2880,7 @@ doUnary: HoistedVar *JS2Metadata::defineHoistedVar(Environment *env, const StringAtom *id, StmtNode *p) { HoistedVar *result = NULL; - QualifiedName qName(publicNamespace, *id); + QualifiedName qName(publicNamespace, id); FrameListIterator regionalFrameMark = env->getRegionalFrame(); Frame *regionalFrame = *regionalFrameMark; ASSERT((regionalFrame->kind == GlobalObjectKind) || (regionalFrame->kind == ParameterKind)); diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index 26816ab73fd3..ed8ed5ed903f 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -55,7 +55,7 @@ class CallableInstance; typedef void (Invokable)(); -typedef Invokable Callor; +typedef js2val (Callor)(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); typedef js2val (Constructor)(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); extern void initDateObject(JS2Metadata *meta); @@ -217,12 +217,12 @@ public: // A QualifiedName is the combination of an identifier and a namespace class QualifiedName { public: - QualifiedName(Namespace *nameSpace, const StringAtom &id) : nameSpace(nameSpace), id(id) { } + QualifiedName(Namespace *nameSpace, const String *id) : nameSpace(nameSpace), id(id) { } - bool operator ==(const QualifiedName &b) { return (nameSpace == b.nameSpace) && (id == b.id); } + bool operator ==(const QualifiedName &b) { return (nameSpace == b.nameSpace) && (*id == *b.id); } Namespace *nameSpace; // The namespace qualifier - const StringAtom &id; // The name + const String *id; // The name }; // A MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup. @@ -239,7 +239,7 @@ public: void addNamespace(NamespaceList *ns); void addNamespace(Context &cxt); - bool matches(QualifiedName &q) { return (*name == q.id) && onList(q.nameSpace); } + bool matches(QualifiedName &q) { return (*name == *q.id) && onList(q.nameSpace); } bool onList(Namespace *nameSpace); NamespaceList nsList; @@ -1035,7 +1035,7 @@ public: InstanceBinding *resolveInstanceMemberName(JS2Class *js2class, Multiname *multiname, Access access, Phase phase); HoistedVar *defineHoistedVar(Environment *env, const StringAtom *id, StmtNode *p); - Multiname *defineStaticMember(Environment *env, const StringAtom *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m, size_t pos); + Multiname *defineStaticMember(Environment *env, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m, size_t pos); OverrideStatusPair *defineInstanceMember(JS2Class *c, Context *cxt, const StringAtom *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, InstanceMember *m, size_t pos); OverrideStatus *resolveOverrides(JS2Class *c, Context *cxt, const StringAtom *id, NamespaceList *namespaces, Access access, bool expectMethod, size_t pos); OverrideStatus *searchForOverrides(JS2Class *c, const StringAtom *id, NamespaceList *namespaces, Access access, size_t pos); diff --git a/js2/src/js2op_invocation.cpp b/js2/src/js2op_invocation.cpp index 89690e41fd12..aad182862778 100644 --- a/js2/src/js2op_invocation.cpp +++ b/js2/src/js2op_invocation.cpp @@ -98,6 +98,8 @@ case eCall: { + // XXX Remove the arguments from the stack, (native calls have done this already) + // (important that they're tracked for gc in any mechanism) uint16 argCount = BytecodeContainer::getShort(pc); pc += sizeof(uint16); a = top(argCount + 2); // 'this' @@ -156,8 +158,18 @@ push(a); } } - // XXX Remove the arguments from the stack, (native calls have done this already) - // (important that they're tracked for gc in any mechanism) + else + if (fObj->kind == ClassKind) { + JS2Class *c = checked_cast(fObj); + if (c->call) + a = c->call(meta, JS2VAL_NULL, base(argCount), argCount); + else + a = JS2VAL_UNDEFINED; + pop(argCount + 1); + push(a); + } + else + meta->reportError(Exception::badValueError, "Un-callable object", errorPos()); } break; @@ -263,4 +275,11 @@ } break; - + case eCoerce: + { + JS2Class *c = BytecodeContainer::getType(pc); + pc += sizeof(JS2Class *); + a = pop(); + push(c->implicitCoerce(meta, a)); + } + break; diff --git a/js2/src/js2op_literal.cpp b/js2/src/js2op_literal.cpp index 36a2f0f05cd6..bd590eb9a6be 100644 --- a/js2/src/js2op_literal.cpp +++ b/js2/src/js2op_literal.cpp @@ -88,6 +88,12 @@ } break; + case eUndefined: + { + push(JS2VAL_UNDEFINED); + } + break; + case eThis: // XXX literal? { a = meta->env->findThis(true); diff --git a/js2/src/js2regexp.cpp b/js2/src/js2regexp.cpp index 27c3a3af10d5..fee9890e155c 100644 --- a/js2/src/js2regexp.cpp +++ b/js2/src/js2regexp.cpp @@ -62,62 +62,62 @@ namespace MetaData { void RegExpInstance::setLastIndex(JS2Metadata *meta, js2val a) { - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["lastIndex"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["lastIndex"]); if (!meta->writeInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, a, RunPhase)) ASSERT(false); } void RegExpInstance::setGlobal(JS2Metadata *meta, js2val a) { - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["global"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["global"]); if (!meta->writeInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, a, RunPhase)) ASSERT(false); } void RegExpInstance::setMultiline(JS2Metadata *meta, js2val a) { - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["multiline"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["multiline"]); if (!meta->writeInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, a, RunPhase)) ASSERT(false); } void RegExpInstance::setIgnoreCase(JS2Metadata *meta, js2val a) { - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["ignoreCase"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["ignoreCase"]); if (!meta->writeInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, a, RunPhase)) ASSERT(false); } void RegExpInstance::setSource(JS2Metadata *meta, js2val a) { - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["source"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["source"]); if (!meta->writeInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, a, RunPhase)) ASSERT(false); } js2val RegExpInstance::getLastIndex(JS2Metadata *meta) { js2val r; - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["lastIndex"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["lastIndex"]); if (!meta->readInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, RunPhase, &r)) ASSERT(false); return r; } js2val RegExpInstance::getGlobal(JS2Metadata *meta) { js2val r; - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["global"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["global"]); if (!meta->readInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, RunPhase, &r)) ASSERT(false); return r; } js2val RegExpInstance::getMultiline(JS2Metadata *meta) { js2val r; - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["multiline"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["multiline"]); if (!meta->readInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, RunPhase, &r)) ASSERT(false); return r; } js2val RegExpInstance::getIgnoreCase(JS2Metadata *meta) { js2val r; - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["ignoreCase"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["ignoreCase"]); if (!meta->readInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, RunPhase, &r)) ASSERT(false); return r; } js2val RegExpInstance::getSource(JS2Metadata *meta) { js2val r; - QualifiedName qname(meta->publicNamespace, meta->world.identifiers["source"]); + QualifiedName qname(meta->publicNamespace, &meta->world.identifiers["source"]); if (!meta->readInstanceMember(OBJECT_TO_JS2VAL(this), meta->regexpClass, &qname, RunPhase, &r)) ASSERT(false); return r; }