diff --git a/mozilla/js2/src/js2array.cpp b/mozilla/js2/src/js2array.cpp index 12d5e00702c..de92d55ebdc 100644 --- a/mozilla/js2/src/js2array.cpp +++ b/mozilla/js2/src/js2array.cpp @@ -58,12 +58,10 @@ namespace MetaData { uint32 getLength(JS2Metadata *meta, JS2Object *obj) { - meta->mn1->name = meta->engine->length_StringAtom; LookupKind lookup(false, JS2VAL_NULL); uint32 length = 0; js2val result; - // XXX why even pass multinames to write/read Dynamic? - if (meta->readDynamicProperty(obj, meta->mn1, &lookup, RunPhase, &result)) + if (meta->readDynamicProperty(obj, meta->engine->length_StringAtom, &lookup, RunPhase, &result)) length = toUInt32(meta->toInteger(result)); return length; } @@ -100,8 +98,7 @@ js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 newLength) checked_cast(obj)->dynamicProperties.insert(dpb->name, dpb); } else { - meta->mn1->name = meta->engine->length_StringAtom; - meta->writeDynamicProperty(obj, meta->mn1, true, result, RunPhase); + meta->writeDynamicProperty(obj, meta->engine->length_StringAtom, true, result, RunPhase); } return result; } @@ -121,8 +118,9 @@ js2val Array_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val * meta->reportError(Exception::rangeError, "Array length too large", meta->engine->errorPos()); } else { - meta->mn1->name = meta->engine->numberToString((int32)0); - meta->writeDynamicProperty(arrInst, meta->mn1, true, argv[0], RunPhase); + String *s = meta->engine->numberToString((int32)0); + RootKeeper rk(&s); + meta->writeDynamicProperty(arrInst, s, true, argv[0], RunPhase); } } else { diff --git a/mozilla/js2/src/js2eval.cpp b/mozilla/js2/src/js2eval.cpp index c7eb328f11e..a878ce5cad9 100644 --- a/mozilla/js2/src/js2eval.cpp +++ b/mozilla/js2/src/js2eval.cpp @@ -446,6 +446,35 @@ namespace MetaData { return JS2VAL_VOID; } + float64 JS2Metadata::convertStringToDouble(const String *str) + { + bool neg = false; + uint32 length = str->length(); + if (length == 0) + return 0.0; + const char16 *numEnd; + // if the string begins with '0X' or '0x' (after white space), then + // read it as a hex integer. + const char16 *strStart = str->data(); + const char16 *strEnd = strStart + length; + const char16 *str1 = skipWhiteSpace(strStart, strEnd); + if (str1 == strEnd) + return 0.0; + if (*str1 == '-') { + neg = true; + str1++; + } + float64 d; + if ((*str1 == '0') && ((str1[1] == 'x') || (str1[1] == 'X'))) + d = stringToInteger(str1, strEnd, numEnd, 16); + else { + d = stringToDouble(str1, strEnd, numEnd); + if (numEnd == str1) + return nan; + } + return (neg) ? -d : d; + } + // x is not a number float64 JS2Metadata::convertValueToDouble(js2val x) { @@ -457,23 +486,7 @@ namespace MetaData { return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0; if (JS2VAL_IS_STRING(x)) { String *str = JS2VAL_TO_STRING(x); - uint32 length = str->length(); - if (length == 0) - return 0.0; - const char16 *numEnd; - // if the string begins with '0X' or '0x' (after white space), then - // read it as a hex integer. - const char16 *strStart = str->data(); - const char16 *strEnd = strStart + length; - const char16 *str1 = skipWhiteSpace(strStart, strEnd); - if ((*str1 == '0') && ((str1[1] == 'x') || (str1[1] == 'X'))) - return stringToInteger(str1, strEnd, numEnd, 16); - else { - float64 d = stringToDouble(str1, strEnd, numEnd); - if (numEnd == str1) - return nan; - return d; - } + return convertStringToDouble(str); } if (JS2VAL_IS_INACCESSIBLE(x)) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos()); diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 37d2bb169bc..02459e52d71 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -444,7 +444,7 @@ namespace MetaData { if (unchecked && (f->attributes == NULL) && ((topFrame->kind == PackageKind) - || (topFrame->kind == BlockKind) + || (topFrame->kind == BlockFrameKind) || (topFrame->kind == ParameterKind)) ) { DynamicVariable *v = defineHoistedVar(env, f->function.name, p); v->value = OBJECT_TO_JS2VAL(fObj); @@ -2364,18 +2364,31 @@ doUnary: return NULL; } - // Returns the most specific regional frame. A regional frame is either any frame other than - // a local block frame or a local block frame whose immediate enclosing frame is a class. + // getRegionalEnvironment(env) returns all frames in env up to and including the first + // regional frame. A regional frame is either any frame other than a with frame or local + // block frame, a local block frame directly enclosed in a class, or a local block frame + // directly enclosed in a with frame directly enclosed in a class. + // In this implementation, the return value is the iterator at the end of the regional environment. + FrameListIterator Environment::getRegionalEnvironment() + { + FrameListIterator start = getBegin(); + FrameListIterator fi = start; + while (((*fi)->kind == BlockFrameKind) || ((*fi)->kind == WithFrameKind)) { + fi++; + ASSERT(fi != getEnd()); + } + if ((*fi)->kind == ClassKind) { + while ((fi != start) && ((*fi)->kind != BlockFrameKind)) + fi--; + } + return fi; + } + + + // Returns the most specific regional frame. FrameListIterator Environment::getRegionalFrame() { - FrameListIterator fi = getBegin(); - while (fi != getEnd()) { - if ((*fi)->kind != BlockKind) - break; - fi++; - } - if ((fi != getBegin()) && ((*fi)->kind == ClassKind)) - fi--; + FrameListIterator fi = getRegionalEnvironment(); return fi; } @@ -2399,8 +2412,9 @@ doUnary: && !JS2VAL_IS_NULL(checked_cast(pf)->thisObject)) if (allowPrototypeThis || !checked_cast(pf)->prototype) return checked_cast(pf)->thisObject; - if (pf->kind == PackageKind) // XXX for ECMA3, when we hit a package (read GlobalObject) - // return that as the 'this' + // XXX for ECMA3, when we hit a package (read GlobalObject) return that as the 'this' + // XXX should have 'ECMA3' compatibility flag in Environment? + if (pf->kind == PackageKind) return OBJECT_TO_JS2VAL(pf); fi++; } @@ -2833,24 +2847,40 @@ doUnary: // variable can be defined using either a var or a function statement. If it is defined using var, then initialValue // is always undefined (if the var statement has an initialiser, then the variable's value will be written later // when the var statement is executed). If it is defined using function, then initialValue must be a function - // instance or open instance. According to rules inherited from ECMAScript Edition 3, if there are multiple - // definitions of a hoisted variable, then the initial value of that variable is undefined if none of the definitions - // is a function definition; otherwise, the initial value is the last function definition. - DynamicVariable *JS2Metadata::defineHoistedVar(Environment *env, const String *id, StmtNode *p) + // instance or open instance. A var hoisted variable may be hoisted into the ParameterFrame if there is already + // a parameter with the same name; a function hoisted variable is never hoisted into the ParameterFrame and + // will shadow a parameter with the same name for compatibility with ECMAScript Edition 3. + // If there are multiple function definitions, the initial value is the last function definition. + + DynamicVariable *JS2Metadata::defineHoistedVar(Environment *env, const String *id, StmtNode *p, bool isVar) { - DynamicVariable *result = NULL; - QualifiedName qName(publicNamespace, id); - FrameListIterator regionalFrameMark = env->getRegionalFrame(); - // XXX can the regionalFrame be a WithFrame? + FrameListIterator regionalFrameEnd = env->getRegionalEnvironment(); NonWithFrame *regionalFrame = checked_cast(*regionalFrameMark); ASSERT((regionalFrame->kind == PackageKind) || (regionalFrame->kind == ParameterKind)); // run through all the existing bindings, to see if this variable already exists. + DynamicVariable *result = NULL; + bool foundMultiple = false; LocalBindingEntry **lbeP = regionalFrame->localBindings[*id]; if (lbeP) { for (LocalBindingEntry::NS_Iterator i = (*lbeP)->begin(), end = (*lbeP)->end(); (i != end); i++) { LocalBindingEntry::NamespaceBinding &ns = *i; if (ns.first == publicNamespace) { + if (result) { + foundMultiple = true; + break; // it's not important to find more than one duplicate (is that even possible?) + } + else + result = checked_cast(ns.second->content); + } + } + } + + if (((result == NULL) || !isVar) + && (regionalFrame->kind == ParameterKind) + && (regionalFrameEnd != env->getBegin())) + + if (ns.second->content->kind != LocalMember::DynamicVariableKind) reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id); else { @@ -2859,10 +2889,7 @@ doUnary: else result = checked_cast(ns.second->content); } - } - } - } - + if (result == NULL) { if (regionalFrame->kind == PackageKind) { Package *gObj = checked_cast(regionalFrame); @@ -3071,7 +3098,7 @@ static const uint8 urlCharType[256] = const char16 *chars = str->data(); uint32 length = str->length(); const char16 *numEnd; - uint base = 10; + uint base = 0; if (argc > 1) { float64 d = meta->toFloat64(argv[1]); @@ -3087,12 +3114,18 @@ static const uint8 urlCharType[256] = return meta->engine->allocNumber(stringToInteger(chars, chars + length, numEnd, base)); } + static js2val GlobalObject_parseFloat(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint32 argc) + { + const String *str = meta->toString(argv[0]); + return meta->engine->allocNumber(meta->convertStringToDouble(str)); + } + void JS2Metadata::addGlobalObjectFunction(char *name, NativeCode *code, uint32 length) { SimpleInstance *fInst = new SimpleInstance(functionClass); fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), code, env); writeDynamicProperty(glob, new Multiname(&world.identifiers[name], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase); - fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(length), DynamicPropertyValue::READONLY); + fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(length), DynamicPropertyValue::READONLY | DynamicPropertyValue::PERMANENT); } static js2val Object_toString(JS2Metadata *meta, const js2val thisValue, js2val /* argv */ [], uint32 /* argc */) @@ -3191,6 +3224,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... addGlobalObjectFunction("unescape", GlobalObject_unescape, 1); addGlobalObjectFunction("escape", GlobalObject_escape, 1); addGlobalObjectFunction("parseInt", GlobalObject_parseInt, 2); + addGlobalObjectFunction("parseFloat", GlobalObject_parseFloat, 1); /*** ECMA 3 Object Class ***/ @@ -3324,7 +3358,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... case SystemKind: case ParameterKind: - case BlockKind: + case BlockFrameKind: default: ASSERT(false); return NULL; @@ -3659,7 +3693,7 @@ readClassProperty: case SystemKind: case PackageKind: case ParameterKind: - case BlockKind: + case BlockFrameKind: case ClassKind: return readProperty(checked_cast(container), multiname, lookupKind, phase, rval); @@ -3787,7 +3821,7 @@ readClassProperty: case SystemKind: case PackageKind: case ParameterKind: - case BlockKind: + case BlockFrameKind: case ClassKind: return writeProperty(checked_cast(container), multiname, lookupKind, createIfMissing, newValue, phase, false); @@ -3900,7 +3934,7 @@ deleteClassProperty: case SystemKind: case PackageKind: case ParameterKind: - case BlockKind: + case BlockFrameKind: case ClassKind: return deleteProperty(checked_cast(container), multiname, lookupKind, phase, result); @@ -4254,7 +4288,7 @@ deleteClassProperty: FunctionInstance *fInst = new FunctionInstance(this, functionClass->prototype, functionClass); fInst->fWrap = callInst->fWrap; writeDynamicProperty(builtinClass->prototype, new Multiname(&world.identifiers[pf->name], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase); - writeDynamicProperty(fInst, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(pf->length), RunPhase); + fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(pf->length), DynamicPropertyValue::READONLY | DynamicPropertyValue::PERMANENT); pf++; } } diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 250cd7dfc40..376452a4ad9 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -106,7 +106,7 @@ enum ObjectKind { PackageKind, ParameterKind, ClassKind, - BlockKind, + BlockFrameKind, PrototypeInstanceKind, SimpleInstanceKind, MultinameKind, @@ -586,6 +586,7 @@ public: JS2Class *getEnclosingClass(); FrameListIterator getRegionalFrame(); + FrameListIterator getRegionalEnvironment(); Frame *getTopFrame() { return frameList.front(); } FrameListIterator getBegin() { return frameList.begin(); } FrameListIterator getEnd() { return frameList.end(); } @@ -1042,8 +1043,8 @@ public: class BlockFrame : public NonWithFrame { public: - BlockFrame() : NonWithFrame(BlockKind) { } - BlockFrame(BlockFrame *pluralFrame) : NonWithFrame(BlockKind, pluralFrame) { } + BlockFrame() : NonWithFrame(BlockFrameKind) { } + BlockFrame(BlockFrame *pluralFrame) : NonWithFrame(BlockFrameKind, pluralFrame) { } Plurality plurality; @@ -1167,7 +1168,7 @@ public: LocalMember *findFlatMember(NonWithFrame *container, Multiname *multiname, Access access, Phase phase); InstanceBinding *resolveInstanceMemberName(JS2Class *js2class, Multiname *multiname, Access access, Phase phase, QualifiedName *qname); - DynamicVariable *defineHoistedVar(Environment *env, const String *id, StmtNode *p); + DynamicVariable *defineHoistedVar(Environment *env, const String *id, StmtNode *p, bool isVar); Multiname *defineLocalMember(Environment *env, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, LocalMember *m, size_t pos); OverrideStatusPair *defineInstanceMember(JS2Class *c, Context *cxt, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, InstanceMember *m, size_t pos); OverrideStatus *resolveOverrides(JS2Class *c, Context *cxt, const String *id, NamespaceList *namespaces, Access access, bool expectMethod, size_t pos); @@ -1183,7 +1184,7 @@ public: bool readProperty(js2val *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); bool readProperty(Frame *pf, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); - bool readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); + bool readDynamicProperty(JS2Object *container, const String *name, LookupKind *lookupKind, Phase phase, js2val *rval); bool readLocalMember(LocalMember *m, Phase phase, js2val *rval); bool readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval); JS2Object *lookupDynamicProperty(JS2Object *obj, const String *name); @@ -1191,13 +1192,13 @@ public: bool writeProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase); bool writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase, bool initFlag); - bool writeDynamicProperty(JS2Object *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase); + bool writeDynamicProperty(JS2Object *container, const String *name, bool createIfMissing, js2val newValue, Phase phase); bool writeLocalMember(LocalMember *m, js2val newValue, Phase phase, bool initFlag); bool writeInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, js2val newValue, Phase phase); bool deleteProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, bool *result); bool deleteProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, Phase phase, bool *result); - bool deleteDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, bool *result); + bool deleteDynamicProperty(JS2Object *container, const String *name, LookupKind *lookupKind, bool *result); bool deleteLocalMember(LocalMember *m, bool *result); bool deleteInstanceMember(JS2Class *c, QualifiedName *qname, bool *result); @@ -1211,6 +1212,7 @@ public: const String *convertValueToString(js2val x); js2val convertValueToPrimitive(js2val x, Hint hint); float64 convertValueToDouble(js2val x); + float64 convertStringToDouble(const String *str); bool convertValueToBoolean(js2val x); int32 convertValueToInteger(js2val x); js2val convertValueToGeneralNumber(js2val x); diff --git a/mozilla/js2/src/lexer.cpp b/mozilla/js2/src/lexer.cpp index 2c07b994ec9..cfa18fcfdf9 100644 --- a/mozilla/js2/src/lexer.cpp +++ b/mozilla/js2/src/lexer.cpp @@ -340,6 +340,7 @@ bool JS::Lexer::lexNumeral() { int hasDecimalPoint = 0; bool hexadecimal = false; + bool octal = false; String &s = nextToken->chars; uint digit; @@ -363,7 +364,14 @@ bool JS::Lexer::lexNumeral() reader.setPos(pos); goto done; } else if (isASCIIDecimalDigit(ch)) { - syntaxError("Numeric constant syntax error"); + // Backward compatible hack, support octal for SpiderMonkey's sake + octal = true; + while (isASCIIDecimalDigit(ch)) { + reader.recordChar(ch); + ch = getChar(); + } + goto done; +// syntaxError("Numeric constant syntax error"); } } while (isASCIIDecimalDigit(ch) || ch == '.' && !hasDecimalPoint++) { @@ -399,7 +407,11 @@ bool JS::Lexer::lexNumeral() const char16 *sBegin = s.data(); const char16 *sEnd = sBegin + s.size(); const char16 *numEnd; - nextToken->value = hexadecimal ? stringToInteger(sBegin, sEnd, numEnd, 16) : stringToDouble(sBegin, sEnd, numEnd); + nextToken->value = hexadecimal ? + stringToInteger(sBegin, sEnd, numEnd, 16) + : octal ? + stringToInteger(sBegin, sEnd, numEnd, 8) + : stringToDouble(sBegin, sEnd, numEnd); ASSERT(numEnd == sEnd); reader.unget(); ASSERT(ch == reader.peek());