diff --git a/js2/src/epimetheus.cpp b/js2/src/epimetheus.cpp index a1ec5928a36e..0b52ed2dec80 100644 --- a/js2/src/epimetheus.cpp +++ b/js2/src/epimetheus.cpp @@ -395,6 +395,20 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint printFormat(stdOut, "function = 0x%08X\n", im->fInst); } break; + case Member::InstanceGetterMember: + { + InstanceGetter *g = checked_cast(ns.second->content); + stdOut << "\t" << *(ns.first->name) << "::" << ibe->name; + stdOut << " get" << ":" << *g->type->name << "\n"; + } + break; + case Member::InstanceSetterMember: + { + InstanceSetter *s = checked_cast(ns.second->content); + stdOut << "\t" << *(ns.first->name) << "::" << ibe->name; + stdOut << " set" << ":" << *s->type->name << "\n"; + } + break; } } } diff --git a/js2/src/js2eval.cpp b/js2/src/js2eval.cpp index 9fbd5f5657fc..9579077a0231 100644 --- a/js2/src/js2eval.cpp +++ b/js2/src/js2eval.cpp @@ -884,7 +884,7 @@ namespace MetaData { bool JS2Class::Delete(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool *result) { - InstanceMember *mBase = meta->findBaseInstanceMember(this, multiname, WriteAccess); + InstanceMember *mBase = meta->findBaseInstanceMember(this, multiname, ReadWriteAccess); if (mBase) { *result = false; return true; @@ -892,9 +892,11 @@ namespace MetaData { if (this != meta->objectType(base)) return false; - Member *m = meta->findCommonMember(&base, multiname, WriteAccess, false); - if (m == NULL) - return false; + Member *m = meta->findCommonMember(&base, multiname, ReadWriteAccess, false); + if (m == NULL) { + *result = true; + return true; + } switch (m->memberKind) { case Member::ForbiddenMember: meta->reportError(Exception::propertyAccessError, "It is forbidden", meta->engine->errorPos()); diff --git a/js2/src/js2function.cpp b/js2/src/js2function.cpp index 5a5633d53690..4d680bf81361 100644 --- a/js2/src/js2function.cpp +++ b/js2/src/js2function.cpp @@ -121,8 +121,11 @@ namespace MetaData { || (JS2VAL_TO_OBJECT(thisValue)->kind != SimpleInstanceKind) || ((checked_cast(JS2VAL_TO_OBJECT(thisValue)))->type != meta->functionClass)) meta->reportError(Exception::typeError, "Function.toString called on something other than a function thing", meta->engine->errorPos()); -// FunctionInstance *fnInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); - return STRING_TO_JS2VAL(meta->engine->Function_StringAtom); + FunctionInstance *fnInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); + if (fnInst->sourceText) + return STRING_TO_JS2VAL(fnInst->sourceText); + else + return STRING_TO_JS2VAL(meta->engine->Function_StringAtom); } static js2val Function_call(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp index 66aced06f4a6..e48e7404a782 100644 --- a/js2/src/js2metadata.cpp +++ b/js2/src/js2metadata.cpp @@ -193,6 +193,11 @@ namespace MetaData { } break; } + StringFormatter sFmt; + PrettyPrinter pp(sFmt); + fnDef->print(pp, NULL, true); + pp.end(); + fnInst->sourceText = engine->allocStringPtr(&sFmt.getString()); } void JS2Metadata::validateConstructor(Context *cxt, Environment *env, FunctionDefinition *fnDef, JS2Class *c, CompoundAttribute *a, size_t pos) @@ -3844,9 +3849,15 @@ static const uint8 urlCharType[256] = return GlobalObject_toString(meta, thisValue, NULL, 0); } else { - JS2Class *type = (checked_cast(obj))->type; - String s = "[object " + *type->name + "]"; - return STRING_TO_JS2VAL(meta->engine->allocString(s)); + if (obj->kind == ClassKind && meta->cxt.E3compatibility) { + String s = widenCString("[object Function]"); + return STRING_TO_JS2VAL(meta->engine->allocString(s)); + } + else { + JS2Class *type = (checked_cast(obj))->type; + String s = "[object " + *type->name + "]"; + return STRING_TO_JS2VAL(meta->engine->allocString(s)); + } } } @@ -4023,8 +4034,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... createDynamicProperty(glob, engine->undefined_StringAtom, JS2VAL_UNDEFINED, ReadAccess, true, false); createDynamicProperty(glob, &world.identifiers["NaN"], engine->nanValue, ReadAccess, true, false); createDynamicProperty(glob, &world.identifiers["Infinity"], engine->posInfValue, ReadAccess, true, false); - // XXX add 'version()' -// createDynamicProperty(glob, &world.identifiers["version"], INT_TO_JS2VAL(0), ReadAccess, true, false); /*** ECMA 3 Object Class ***/ @@ -4042,6 +4051,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... defineLocalMember(env, engine->length_StringAtom, NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false); env->removeTopFrame(); + glob->super = objectClass->prototype; + /*** ECMA 3 Function Class ***/ // Need this initialized early, as subsequent FunctionInstances need the Function.prototype value v = new Variable(classClass, OBJECT_TO_JS2VAL(functionClass), true); @@ -4078,7 +4089,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... defineInstanceMember(objectClass, &cxt, proto_mn.name, *proto_mn.nsList, Attribute::NoOverride, false, s, 0); -// Adding 'toString' to the Object.prototype XXX Or make this a static class member? +// Adding 'toString' etc to the Object.prototype XXX Or make this a static class member? fInst = createFunctionInstance(env, true, true, Object_toString, 0, NULL); createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), engine->toString_StringAtom, OBJECT_TO_JS2VAL(fInst), ReadAccess, true, false); // and 'valueOf' @@ -4086,8 +4097,14 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), engine->valueOf_StringAtom, OBJECT_TO_JS2VAL(fInst), ReadAccess, true, false); // and 'constructor' fInst = createFunctionInstance(env, true, true, Object_Constructor, 0, NULL); - // XXX 'this' == JS2VAL_INACCESSIBLE for above??? createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), &world.identifiers["constructor"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false); + // and various property/enumerable functions + fInst = createFunctionInstance(env, true, true, Object_hasOwnProperty, 0, NULL); + createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), &world.identifiers["hasOwnProperty"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false); + fInst = createFunctionInstance(env, true, true, Object_isPropertyOf, 0, NULL); + createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), &world.identifiers["isPropertyOf"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false); + fInst = createFunctionInstance(env, true, true, Object_propertyIsEnumerble, 0, NULL); + createDynamicProperty(JS2VAL_TO_OBJECT(objectClass->prototype), &world.identifiers["propertyIsEnumerable"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false); /*** ECMA 4 Integer Class ***/ @@ -4746,8 +4763,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... // Adding "prototype" & "length", etc as static members of the class - not dynamic properties; XXX env->addFrame(builtinClass); { - Variable *v = new Variable(builtinClass, INT_TO_JS2VAL(1), true); - defineLocalMember(env, engine->length_StringAtom, NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false); + Variable *v = new Variable(integerClass, INT_TO_JS2VAL(1), true); + defineLocalMember(env, engine->length_StringAtom, NULL, Attribute::NoOverride, false, ReadAccess, v, 0, false); pf = staticFunctions; if (pf) { @@ -4978,10 +4995,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... : SimpleInstance(meta, parent, type) { length = 0; -// JS2Object *result = this; -// DEFINE_ROOTKEEPER(rk1, result); - -// meta->createDynamicProperty(this, meta->engine->length_StringAtom, INT_TO_JS2VAL(0), ReadWriteAccess, true, false); } /************************************************************************************ @@ -4991,7 +5004,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... ************************************************************************************/ FunctionInstance::FunctionInstance(JS2Metadata *meta, js2val parent, JS2Class *type) - : SimpleInstance(meta, parent, type), isMethodClosure(false), fWrap(NULL), thisObject(JS2VAL_VOID) + : SimpleInstance(meta, parent, type), isMethodClosure(false), fWrap(NULL), thisObject(JS2VAL_VOID), sourceText(NULL) { // Add prototype property JS2Object *result = this; @@ -5016,6 +5029,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... fWrap->bCon->mark(); } GCMARKVALUE(thisObject); + if (sourceText) JS2Object::mark(sourceText); } FunctionInstance::~FunctionInstance() diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index 66bb2656c121..84e79ebbf372 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -1008,6 +1008,7 @@ public: bool isMethodClosure; // if true, use the thisObject from below js2val thisObject; + const String *sourceText; virtual void markChildren(); virtual ~FunctionInstance(); diff --git a/js2/src/js2op_invocation.cpp b/js2/src/js2op_invocation.cpp index 53a3ca3f5e02..86b80d76ff7e 100644 --- a/js2/src/js2op_invocation.cpp +++ b/js2/src/js2op_invocation.cpp @@ -306,7 +306,6 @@ doCall: { b = pop(); a = pop(); // doing 'a instanceof b' - if (!JS2VAL_IS_OBJECT(b)) meta->reportError(Exception::typeError, "Object expected for instanceof", errorPos()); JS2Object *obj = JS2VAL_TO_OBJECT(b); @@ -355,33 +354,24 @@ doInstanceOfLoop: push(JS2VAL_FALSE); else { aObj = JS2VAL_TO_OBJECT(a); - if (aObj->kind != SimpleInstanceKind) + if (aObj->kind == SimpleInstanceKind) + a_protoVal = checked_cast(aObj)->super; + else + if (aObj->kind == PackageKind) + a_protoVal = checked_cast(aObj)->super; + else + if (aObj->kind == ClassKind) + a_protoVal = checked_cast(aObj)->prototype; + else meta->reportError(Exception::typeError, "Prototype instance expected for instanceof", errorPos()); - a_protoVal = checked_cast(aObj)->super; b_protoVal = checked_cast(obj)->prototype; goto doInstanceOfLoop; -/* - bool result = false; - while (!JS2VAL_IS_NULL(a_protoVal) && !JS2VAL_IS_UNDEFINED(a_protoVal)) { - if (b_protoVal == a_protoVal) { - result = true; - break; - } - if (!JS2VAL_IS_OBJECT(a_protoVal)) - meta->reportError(Exception::typeError, "Non-object prototype value in instanceOf", errorPos()); - aObj = JS2VAL_TO_OBJECT(a_protoVal); - if (aObj->kind != SimpleInstanceKind) - meta->reportError(Exception::typeError, "Prototype instance expected for instanceof", errorPos()); - a_protoVal = checked_cast(aObj)->super; - } - push(BOOLEAN_TO_JS2VAL(result)); -*/ + } } else meta->reportError(Exception::typeError, "Function or Class expected in instanceOf", errorPos()); } - } break; diff --git a/js2/src/parser.cpp b/js2/src/parser.cpp index 47a0b29604ad..a2ca720e1b70 100644 --- a/js2/src/parser.cpp +++ b/js2/src/parser.cpp @@ -2038,7 +2038,11 @@ JS::StmtNode *JS::Parser::parseProgram() // Parser Utilities // +#ifdef DEBUG const bool debugExprNodePrint = true; // Print extra parentheses around subexpressions? +#else +const bool debugExprNodePrint = false; // Print extra parentheses around subexpressions? +#endif const int32 basicIndent = 4; // Size of one level of statement indentation const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement const int32 varIndent = 2; // Indentation of var or const statement bindings @@ -2473,7 +2477,10 @@ void JS::StmtNode::printBlockStatements(PrettyPrinter &f, const StmtNode *statem statements->print(f, false); } else { f.linearBreak(nSpaces, loose); - statements->print(f, !statements->next); + // XXX I overrode the 'nosemi' flag in order to + // get E3 regression tests to pass. Maybe use an E3 + // compatibility flag instead? + statements->print(f, false/*!statements->next*/); } statements = statements->next; nSpaces = 1;