Incremental ECMA compatibility fixings.

This commit is contained in:
rogerl%netscape.com 2002-01-18 02:03:56 +00:00
Родитель 3b54ba6a7a
Коммит 91cbb70b0f
7 изменённых файлов: 239 добавлений и 62 удалений

Просмотреть файл

@ -238,11 +238,12 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
mStack = prev->mStack;
mStackTop = 0; // we're processing an exception, no need to preserve the stack
if (jsx.hasKind(Exception::userException))
pushValue(x);
if (mCurModule)
mStackMax = mCurModule->mStackDepth;
if (mCurModule) {
mStackMax = mCurModule->mStackDepth;
if (jsx.hasKind(Exception::userException))
pushValue(x);
}
mLocals = prev->mLocals;
mArgumentBase = prev->mArgumentBase;
mThis = prev->mThis;
@ -331,7 +332,7 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
needDefault = false;
}
}
if (needDefault)
if (needDefault && target->isChecked())
reportError(Exception::referenceError, "missing required argument");
}
else {

Просмотреть файл

@ -636,7 +636,8 @@ void JSInstance::initInstance(Context *cx, JSType *type)
JSInstance *JSType::newInstance(Context *cx)
{
JSInstance *result = new JSInstance(cx, this);
result->mPrototype = mPrototypeObject;
result->mPrototype = mPrototypeObject;
result->defineVariable(cx, cx->UnderbarPrototype_StringAtom, NULL, 0, Object_Type, JSValue(mPrototypeObject));
return result;
}
@ -666,6 +667,7 @@ JSInstance *JSArrayType::newInstance(Context *cx)
{
JSInstance *result = new JSArrayInstance(cx, this);
result->mPrototype = mPrototypeObject;
result->defineVariable(cx, cx->UnderbarPrototype_StringAtom, NULL, 0, Object_Type, JSValue(mPrototypeObject));
return result;
}
@ -673,6 +675,7 @@ JSInstance *JSStringType::newInstance(Context *cx)
{
JSInstance *result = new JSStringInstance(cx, this);
result->mPrototype = mPrototypeObject;
result->defineVariable(cx, cx->UnderbarPrototype_StringAtom, NULL, 0, Object_Type, JSValue(mPrototypeObject));
return result;
}
@ -1575,7 +1578,7 @@ Reference *JSType::genReference(bool hasBase, const String& name, NamespaceList
return NULL;
}
JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj)
JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj, JSObject *typeProto)
: JSObject(Type_Type),
mSuperType(super),
mVariableCount(0),
@ -1610,11 +1613,17 @@ JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *pro
else // must be Object_Type being initialized
defineVariable(cx, cx->Prototype_StringAtom, (NamespaceList *)NULL, Property::ReadOnly | Property::DontDelete, this, JSValue(mPrototypeObject));
// the __proto__ of a type is the super-type's prototype object, or for 'class Object' type object it's the Object's prototype object
if (mSuperType)
mPrototype = mSuperType->mPrototypeObject;
else // must be Object_Type being initialized
mPrototype = mPrototypeObject;
if (typeProto)
mPrototype = typeProto;
else {
// the __proto__ of a type is the super-type's prototype object, or for 'class Object' type object it's the Object's prototype object
if (mSuperType)
mPrototype = mSuperType->mPrototypeObject;
else // must be Object_Type being initialized
mPrototype = mPrototypeObject;
}
defineVariable(cx, cx->UnderbarPrototype_StringAtom, NULL, 0, Object_Type, JSValue(mPrototype));
defineVariable(cx, cx->Constructor_StringAtom, (NamespaceList *)NULL, 0, Object_Type, JSValue(this));
}
JSType::JSType(JSType *xClass) // used for constructing the static component type
@ -2953,8 +2962,7 @@ void Context::initBuiltins()
Object_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL);
Object_Type->mPrototype->mType = Object_Type;
Object_Type->mIsDynamic = true;
// XXX aren't all the built-ins thus?
Object_Type->mIsDynamic = true; // XXX aren't all the built-ins thus?
Type_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[1].name)], Object_Type);
Object_Type->mType = Type_Type;
@ -2966,9 +2974,15 @@ void Context::initBuiltins()
// (which we don't actually have, hmm).
// For String, etc. this same issue needs to be finessed
JSFunction *funProto = new JSFunction(this, Object_Type, NULL);
JSFunction *funProto = new JSFunction(this, Object_Type, NULL);
funProto->mPrototype = Object_Type->mPrototypeObject;
Function_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type, funProto);
funProto->mType = Function_Type;
Function_Type->mPrototype = Function_Type->mPrototypeObject;
funProto->mType = Function_Type;
// now we can bootstrap the Object prototype (__proto__) to be the Function prototype
Object_Type->mPrototype = Function_Type->mPrototypeObject;
JSObject *numProto = new JSObject();
Number_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type, numProto);
@ -2982,8 +2996,8 @@ void Context::initBuiltins()
strProto->mType = String_Type;
strProto->mPrivate = (void *)(&Empty_StringAtom);
JSArrayInstance *arrayProto = new JSArrayInstance(this, NULL);
Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type, arrayProto);
JSArrayInstance *arrayProto = new JSArrayInstance(this, NULL);
Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type, arrayProto, Function_Type->mPrototypeObject);
arrayProto->mType = Array_Type;
Boolean_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[7].name)], Object_Type);
@ -3001,7 +3015,7 @@ void Context::initBuiltins()
TypeError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[19].name)], Error_Type);
UriError_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[20].name)], Error_Type);
// XXX RegExp.prototype is set to a RegExp instance, which isn't ECMA (it's supposed to be an Object instance) bu
// XXX RegExp.prototype is set to a RegExp instance, which isn't ECMA (it's supposed to be an Object instance) but
// is SpiderMonkey compatible.
RegExp_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[21].name)], Object_Type);
Package_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[22].name)], Object_Type);
@ -3241,6 +3255,7 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags)
LeftContext_StringAtom (world.identifiers["leftContext"]),
RightContext_StringAtom (world.identifiers["rightContext"]),
Dollar_StringAtom (world.identifiers["$"]),
UnderbarPrototype_StringAtom (world.identifiers["__proto__"]),
mWorld(world),
mScopeChain(NULL),

Просмотреть файл

@ -753,7 +753,7 @@ XXX ...couldn't get this to work...
class JSType : public JSObject {
public:
JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL);
JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL);
JSType(JSType *xClass); // used for constructing the static component type
virtual ~JSType() { } // keeping gcc happy
@ -918,8 +918,8 @@ XXX ...couldn't get this to work...
class JSArrayType : public JSType {
public:
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super, JSObject *protoObj = NULL)
: JSType(cx, name, super, protoObj), mElementType(elementType)
JSArrayType(Context *cx, JSType *elementType, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL)
: JSType(cx, name, super, protoObj, typeProto), mElementType(elementType)
{
}
virtual ~JSArrayType() { } // keeping gcc happy
@ -954,8 +954,8 @@ XXX ...couldn't get this to work...
class JSStringType : public JSType {
public:
JSStringType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL)
: JSType(cx, name, super, protoObj)
JSStringType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL, JSObject *typeProto = NULL)
: JSType(cx, name, super, protoObj, typeProto)
{
}
virtual ~JSStringType() { } // keeping gcc happy
@ -1687,7 +1687,8 @@ XXX ...couldn't get this to work...
StringAtom& LastParen_StringAtom;
StringAtom& LeftContext_StringAtom;
StringAtom& RightContext_StringAtom;
StringAtom& Dollar_StringAtom;
StringAtom& Dollar_StringAtom;
StringAtom& UnderbarPrototype_StringAtom;
void initBuiltins();
void initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef);

Просмотреть файл

@ -218,10 +218,15 @@ static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv,
thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR);
JSValue result = cx->popValue();
uint32 length = (uint32)(result.toUInt32(cx).f64);
/* XXX ECMA says that if separator is undefined we use ',', but SpiderMonkey and
the test suite want 'undefined' in that case, and only use the ',' when the
separator is actually is missing
*/
const String *separator;
if (argc == 0)
separator = new String(',', 1);
separator = new String(widenCString(","));
else
separator = argv[0].toString(cx).string;
@ -231,7 +236,7 @@ static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv,
String *S = new String();
for (uint32 k = 0; k < length; k++) {
thisObj->getProperty(cx, *numberToString(0), CURRENT_ATTR);
thisObj->getProperty(cx, *numberToString(k), CURRENT_ATTR);
result = cx->popValue();
if (!result.isUndefined() && !result.isNull())
*S += *result.toString(cx).string;

Просмотреть файл

@ -43,6 +43,8 @@
#include "parser.h"
#include "numerics.h"
#include "js2runtime.h"
#include "jslong.h"
#include "prmjtime.h"
#include "jsmath.h"
@ -175,10 +177,82 @@ static JSValue Math_pow(Context *cx, const JSValue& /*thisValue*/, JSValue *argv
if (argc < 1)
return kNaNValue;
return JSValue(fd::pow(argv[0].toNumber(cx).f64, argv[1].toNumber(cx).f64));
}
static JSValue Math_random(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue * /*argv*/, uint32 /*argc*/)
}
/*
* Math.random() support, lifted from java.util.Random.java.
*/
static void random_setSeed(Context *cx, int64 seed)
{
int64 tmp;
JSLL_I2L(tmp, 1000);
JSLL_DIV(seed, seed, tmp);
JSLL_XOR(tmp, seed, cx->mWorld.rngMultiplier);
JSLL_AND(cx->mWorld.rngSeed, tmp, cx->mWorld.rngMask);
}
static void random_init(Context *cx)
{
int64 tmp, tmp2;
/* Do at most once. */
if (cx->mWorld.rngInitialized)
return;
cx->mWorld.rngInitialized = true;
/* cx->mWorld.rngMultiplier = 0x5DEECE66DL */
JSLL_ISHL(tmp, 0x5D, 32);
JSLL_UI2L(tmp2, 0xEECE66DL);
JSLL_OR(cx->mWorld.rngMultiplier, tmp, tmp2);
/* cx->mWorld.rngAddend = 0xBL */
JSLL_I2L(cx->mWorld.rngAddend, 0xBL);
/* cx->mWorld.rngMask = (1L << 48) - 1 */
JSLL_I2L(tmp, 1);
JSLL_SHL(tmp2, tmp, 48);
JSLL_SUB(cx->mWorld.rngMask, tmp2, tmp);
/* cx->mWorld.rngDscale = (jsdouble)(1L << 54) */
JSLL_SHL(tmp2, tmp, 54);
JSLL_L2D(cx->mWorld.rngDscale, tmp2);
/* Finally, set the seed from current time. */
random_setSeed(cx, PRMJ_Now());
}
static uint32 random_next(Context *cx, int bits)
{
int64 nextseed, tmp;
uint32 retval;
JSLL_MUL(nextseed, cx->mWorld.rngSeed, cx->mWorld.rngMultiplier);
JSLL_ADD(nextseed, nextseed, cx->mWorld.rngAddend);
JSLL_AND(nextseed, nextseed, cx->mWorld.rngMask);
cx->mWorld.rngSeed = nextseed;
JSLL_USHR(tmp, nextseed, 48 - bits);
JSLL_L2I(retval, tmp);
return retval;
}
static float64 random_nextDouble(Context *cx)
{
int64 tmp, tmp2;
float64 d;
JSLL_ISHL(tmp, random_next(cx, 27), 27);
JSLL_UI2L(tmp2, random_next(cx, 27));
JSLL_ADD(tmp, tmp, tmp2);
JSLL_L2D(d, tmp);
return d / cx->mWorld.rngDscale;
}
static JSValue Math_random(Context *cx, const JSValue& /*thisValue*/, JSValue * /*argv*/, uint32 /*argc*/)
{
return JSValue(42.0);
random_init(cx);
return JSValue(random_nextDouble(cx));
}
static JSValue Math_round(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc)
{

Просмотреть файл

@ -105,6 +105,32 @@ static JSValue String_valueOf(Context *cx, const JSValue& thisValue, JSValue * /
return JSValue((String *)thisObj->mPrivate);
}
static JSValue String_search(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType());
JSValue S = thisValue.toString(cx);
JSValue regexp = argv[0];
if ((argc == 0) || !regexp.isObject() || (regexp.object->mType != RegExp_Type)) {
regexp = kNullValue;
regexp = RegExp_Constructor(cx, regexp, argv, 1);
}
REParseState *parseResult = (REParseState *)(regexp.object->mPrivate);
/* save & restore lastIndex as it's not to be modified */
uint32 lastIndex = parseResult->lastIndex;
parseResult->lastIndex = 0;
REState *regexp_result = REExecute(parseResult, S.string->begin(), S.string->length());
parseResult->lastIndex = lastIndex;
if (regexp_result)
return JSValue((float64)(regexp_result->endIndex));
else
return JSValue(-1.0);
}
static JSValue String_match(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
@ -273,27 +299,60 @@ static JSValue String_replace(Context *cx, const JSValue& thisValue, JSValue *ar
struct MatchResult {
bool failure;
uint32 endIndex;
String **captures;
uint32 endIndex;
uint32 capturesCount;
JSValue *captures;
};
static void splitMatch(const String *S, uint32 q, const String *R, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
uint32 r = R->size();
uint32 s = S->size();
if ((q + r) > s)
return;
for (uint32 i = 0; i < r; i++) {
if ((*S)[q + i] != (*R)[i])
return;
}
result.endIndex = q + r;
result.failure = false;
}
static void strSplitMatch(const String *S, uint32 q, const String *R, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
result.capturesCount = 0;
uint32 r = R->size();
uint32 s = S->size();
if ((q + r) > s)
return;
for (uint32 i = 0; i < r; i++) {
if ((*S)[q + i] != (*R)[i])
return;
}
result.endIndex = q + r;
result.failure = false;
}
static void regexpSplitMatch(const String *S, uint32 q, REParseState *RE, MatchResult &result)
{
result.failure = true;
result.captures = NULL;
/* save & restore lastIndex as it's not to be modified */
uint32 lastIndex = RE->lastIndex;
RE->lastIndex = 0;
REState *regexp_result = REExecute(RE, S->begin() + q, S->length() - q);
RE->lastIndex = lastIndex;
if (regexp_result) {
result.endIndex = regexp_result->endIndex + q;
result.failure = false;
result.capturesCount = regexp_result->n;
if (regexp_result->n) {
result.captures = new JSValue[regexp_result->n];
for (uint32 i = 0; i < regexp_result->n; i++) {
if (regexp_result->parens[i].index != -1) {
String *parenStr = new String(S->substr((uint32)(regexp_result->parens[i].index + q), (uint32)(regexp_result->parens[i].length)));
result.captures[i] = JSValue(parenStr);
}
else
result.captures[i] = kUndefinedValue;
}
}
}
}
static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
{
ContextStackReplacement csr(cx);
@ -313,10 +372,13 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv
uint32 s = S.string->size();
uint32 p = 0;
// XXX if separatorV.isRegExp() -->
const String *R = separatorV.toString(cx).string;
REParseState *RE = NULL;
const String *R = NULL;
if (separatorV.isObject() && (separatorV.object->mType == RegExp_Type))
RE = (REParseState *)(separatorV.object->mPrivate);
else
R = separatorV.toString(cx).string;
if (lim == 0)
return JSValue(A);
@ -330,13 +392,16 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv
*/
if (s == 0) {
MatchResult z;
splitMatch(S.string, 0, R, z);
if (RE)
regexpSplitMatch(S.string, 0, RE, z);
else
strSplitMatch(S.string, 0, R, z);
if (!z.failure)
return JSValue(A);
A->setProperty(cx, widenCString("0"), NULL, S);
return JSValue(A);
}
while (true) {
uint32 q = p;
step11:
@ -346,8 +411,11 @@ step11:
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
return JSValue(A);
}
MatchResult z;
splitMatch(S.string, q, R, z);
MatchResult z;
if (RE)
regexpSplitMatch(S.string, q, RE, z);
else
strSplitMatch(S.string, q, R, z);
if (z.failure) {
q = q + 1;
goto step11;
@ -362,10 +430,14 @@ step11:
A->setProperty(cx, *numberToString(A->mLength), NULL, v);
if (A->mLength == lim)
return JSValue(A);
p = e;
// step 20 --> 27, handle captures array (we know it's empty for non regexp)
p = e;
for (uint32 i = 0; i < z.capturesCount; i++) {
A->setProperty(cx, *numberToString(A->mLength), NULL, JSValue(z.captures[i]));
if (A->mLength == lim)
return JSValue(A);
}
}
}
static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc)
@ -616,7 +688,8 @@ Context::PrototypeFunctions *getStringProtos()
{ "localeCompare", Number_Type, 1, String_localeCompare },
{ "match", Array_Type, 1, String_match },
{ "replace", String_Type, 2, String_replace },
{ "slice", String_Type, 2, String_slice },
{ "search", Number_Type, 1, String_search },
{ "slice", String_Type, 2, String_slice },
{ "split", Array_Type, 1, String_split }, // XXX ECMA spec says 2, but tests want 1 XXX
{ "substring", String_Type, 2, String_substring },
{ "toSource", String_Type, 0, String_toString },

Просмотреть файл

@ -75,7 +75,15 @@ namespace JavaScript {
public:
StringAtomTable identifiers;
World();
World();
/* Random number generator state, used by jsmath.c. */
bool rngInitialized;
int64 rngMultiplier;
int64 rngAddend;
int64 rngMask;
int64 rngSeed;
float64 rngDscale;
};
}
#endif