More ECMA 3 mucking about to support constructors etc.

This commit is contained in:
rogerl%netscape.com 2000-07-25 22:58:04 +00:00
Родитель 20e63b772d
Коммит c30779b359
22 изменённых файлов: 210 добавлений и 74 удалений

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

@ -41,7 +41,7 @@
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
OR, /* dest, source1, source2 */
@ -582,18 +582,18 @@
}
};
class NewObject : public Instruction_1<TypedRegister> {
class NewObject : public Instruction_2<TypedRegister, TypedRegister> {
public:
/* dest */
NewObject (TypedRegister aOp1) :
Instruction_1<TypedRegister>
(NEW_OBJECT, aOp1) {};
/* dest, constructor */
NewObject (TypedRegister aOp1, TypedRegister aOp2) :
Instruction_2<TypedRegister, TypedRegister>
(NEW_OBJECT, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_OBJECT] << "\t" << mOp1;
f << opcodeNames[NEW_OBJECT] << "\t" << mOp1 << ", " << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << mOp1.first;
f << mOp1.first << ", " << mOp2.first;
return f;
}
};

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

@ -211,10 +211,10 @@ TypedRegister ICodeGenerator::loadBoolean(bool value)
return dest;
}
TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/)
TypedRegister ICodeGenerator::newObject(TypedRegister constructor)
{
TypedRegister dest(getTempRegister(), &Any_Type);
NewObject *instr = new NewObject(dest);
NewObject *instr = new NewObject(dest, constructor);
iCode->push_back(instr);
return dest;
}
@ -1103,11 +1103,19 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
call(getStatic(clazz, className), ret, &args);
}
else
NOT_REACHED("New <name>, where <name> is not a known class"); // XXX Runtime error.
NOT_REACHED("new <name>, where <name> is not a new-able type (whatever that means)"); // XXX Runtime error.
}
else
if (value.isFunction()) {
TypedRegister f = loadName(className, value.type);
ret = newObject(f);
call(f, ret, &args);
}
else
NOT_REACHED("new <name>, where <name> is not a function"); // XXX Runtime error.
}
else
ret = newObject(&args); // XXX more ?
ret = newObject(TypedRegister(NotARegister, &Any_Type)); // XXX more ?
}
break;
case ExprNode::Delete:
@ -1449,7 +1457,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::objectLiteral:
{
ret = newObject(NULL);
ret = newObject(TypedRegister(NotARegister, &Any_Type));
PairListExprNode *plen = static_cast<PairListExprNode *>(p);
ExprPairList *e = plen->pairs;
while (e) {

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

@ -254,7 +254,7 @@ namespace ICG {
TypedRegister loadString(const String &value);
TypedRegister loadString(const StringAtom &name);
TypedRegister newObject(RegisterList *args);
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newClass(JSClass *clazz);

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

@ -500,13 +500,17 @@ void Context::initContext()
// set up the correct [[Class]] for the global object (matching SpiderMonkey)
mGlobal->setClass(new JSString("global"));
// add (XXX some) of the global object properties
mGlobal->setProperty(widenCString("NaN"), kNaNValue);
mGlobal->setProperty(widenCString("undefined"), kUndefinedValue);
// 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object
mGlobal->setProperty(widenCString("Math"), JSValue(new JSMath()));
JSObject::initObjectObject(mGlobal);
// the 'Math' object just has some useful properties
JSMath::initMathObject(mGlobal);
// This initializes the state of the binary operator overload mechanism.
@ -712,7 +716,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
NewObject* no = static_cast<NewObject*>(instruction);
JSObject *obj = new JSObject();
(*registers)[dst(no).first] = new JSObject();
if (src1(no).first != NotARegister)
(*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]);
else
(*registers)[dst(no).first] = new JSObject();
}
break;
case NEW_CLASS:

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

@ -235,6 +235,7 @@ static void readEvalPrint(FILE *in, World &world)
// list of zero or more statements
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
if (icm) {
stdOut << *icm;
JSValue result = cx.interpret(icm, JSValues());
stdOut << "result = " << result << "\n";
delete icm;

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

@ -186,18 +186,23 @@ struct MathConstantEntry {
{ "SQRT1_2", M_SQRT1_2 }
};
JSMath::JSMath()
{
setClass(new JSString("Math"));
// There is no constructor for Math, we simply initialize
// the properties of the Math object
void JSMath::initMathObject(JSScope *g)
{
int i;
JSMath *m = new JSMath();
m->setClass(new JSString("Math"));
for (int i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (int i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
g->setProperty(widenCString("Math"), JSValue(m));
}
} /* JSMathClass */
} /* JavaScript */

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

@ -41,11 +41,13 @@ namespace JSMathClass {
using JSTypes::JSObject;
using JSTypes::JSString;
using JSTypes::JSScope;
class JSMath : public JSObject {
private:
JSMath() { }
public:
JSMath();
static void initMathObject(JSScope *g);
};

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

@ -55,17 +55,49 @@ JSValue object_toString(Context *cx, const JSValues& argv)
return kUndefinedValue;
}
JSValue objectConstructor(Context *cx, const JSValues& argv)
{
ASSERT(argv.size() > 0);
JSValue theThis = argv[0];
// the prototype and class have been established already
return theThis;
}
struct ObjectFunctionEntry {
char *name;
JSNativeFunction::JSCode fn;
} ObjectFunctions[] = {
{ "toString", object_toString },
};
JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject();
JSString *JSObject::ObjectString = new JSString("Object");
String JSObject::ObjectString = widenCString("Object");
// This establishes the ur-prototype, there's a timing issue
// here - the JSObject static initializers have to run before
// any other JSObject objects are constructed.
JSObject *JSObject::initJSObject()
{
JSObject *result = new JSObject();
result->setProperty(widenCString("toString"), JSValue(new JSNativeFunction(object_toString) ) );
for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++)
result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) );
return result;
}
// Install the 'Object' constructor into the scope, mostly irrelevant since making
// a new JSObject does all the work of setting the prototype and [[class]] values.
void JSObject::initObjectObject(JSScope *g)
{
JSObject* o = new JSObject();
g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor)));
}

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

@ -60,6 +60,7 @@ namespace JSTypes {
class JSObject;
class JSArray;
class JSFunction;
class JSScope;
class JSString;
class JSType;
class Context;
@ -224,12 +225,17 @@ namespace JSTypes {
JSType* mType;
JSString* mClass; // this is the internal [[Class]] property
public:
JSObject() : mPrototype(objectPrototypeObject), mType(&Any_Type), mClass(ObjectString) {}
static JSObject *objectPrototypeObject;
static JSObject *initJSObject();
static JSString *ObjectString;
static String ObjectString;
static JSObject *objectPrototypeObject;
void init(JSObject* prototype);
public:
JSObject() { init(objectPrototypeObject); }
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
static void initObjectObject(JSScope *g);
bool hasProperty(const String& name)
{
@ -551,6 +557,9 @@ namespace JSTypes {
};
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
} /* namespace JSTypes */
} /* namespace JavaScript */

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

@ -128,9 +128,9 @@ $ops{"SAVE_NAME"} =
};
$ops{"NEW_OBJECT"} =
{
super => "Instruction_1",
rem => "dest",
params => [ ("TypedRegister") ]
super => "Instruction_2",
rem => "dest, constructor",
params => [ ("TypedRegister", "TypedRegister") ]
};
$ops{"NEW_CLASS"} =
{

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

@ -195,6 +195,10 @@ SOURCE=..\jsclasses.h
# End Source File
# Begin Source File
SOURCE=..\jsmath.h
# End Source File
# Begin Source File
SOURCE=..\jstypes.h
# End Source File
# Begin Source File

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

@ -41,7 +41,7 @@
NEW_ARRAY, /* dest */
NEW_CLASS, /* dest, class */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest */
NEW_OBJECT, /* dest, constructor */
NOP, /* do nothing and like it */
NOT, /* dest, source */
OR, /* dest, source1, source2 */
@ -582,18 +582,18 @@
}
};
class NewObject : public Instruction_1<TypedRegister> {
class NewObject : public Instruction_2<TypedRegister, TypedRegister> {
public:
/* dest */
NewObject (TypedRegister aOp1) :
Instruction_1<TypedRegister>
(NEW_OBJECT, aOp1) {};
/* dest, constructor */
NewObject (TypedRegister aOp1, TypedRegister aOp2) :
Instruction_2<TypedRegister, TypedRegister>
(NEW_OBJECT, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_OBJECT] << "\t" << mOp1;
f << opcodeNames[NEW_OBJECT] << "\t" << mOp1 << ", " << mOp2;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << mOp1.first;
f << mOp1.first << ", " << mOp2.first;
return f;
}
};

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

@ -211,10 +211,10 @@ TypedRegister ICodeGenerator::loadBoolean(bool value)
return dest;
}
TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/)
TypedRegister ICodeGenerator::newObject(TypedRegister constructor)
{
TypedRegister dest(getTempRegister(), &Any_Type);
NewObject *instr = new NewObject(dest);
NewObject *instr = new NewObject(dest, constructor);
iCode->push_back(instr);
return dest;
}
@ -1103,11 +1103,19 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
call(getStatic(clazz, className), ret, &args);
}
else
NOT_REACHED("New <name>, where <name> is not a known class"); // XXX Runtime error.
NOT_REACHED("new <name>, where <name> is not a new-able type (whatever that means)"); // XXX Runtime error.
}
else
if (value.isFunction()) {
TypedRegister f = loadName(className, value.type);
ret = newObject(f);
call(f, ret, &args);
}
else
NOT_REACHED("new <name>, where <name> is not a function"); // XXX Runtime error.
}
else
ret = newObject(&args); // XXX more ?
ret = newObject(TypedRegister(NotARegister, &Any_Type)); // XXX more ?
}
break;
case ExprNode::Delete:
@ -1449,7 +1457,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::objectLiteral:
{
ret = newObject(NULL);
ret = newObject(TypedRegister(NotARegister, &Any_Type));
PairListExprNode *plen = static_cast<PairListExprNode *>(p);
ExprPairList *e = plen->pairs;
while (e) {

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

@ -254,7 +254,7 @@ namespace ICG {
TypedRegister loadString(const String &value);
TypedRegister loadString(const StringAtom &name);
TypedRegister newObject(RegisterList *args);
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newClass(JSClass *clazz);

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

@ -500,13 +500,17 @@ void Context::initContext()
// set up the correct [[Class]] for the global object (matching SpiderMonkey)
mGlobal->setClass(new JSString("global"));
// add (XXX some) of the global object properties
mGlobal->setProperty(widenCString("NaN"), kNaNValue);
mGlobal->setProperty(widenCString("undefined"), kUndefinedValue);
// 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object
mGlobal->setProperty(widenCString("Math"), JSValue(new JSMath()));
JSObject::initObjectObject(mGlobal);
// the 'Math' object just has some useful properties
JSMath::initMathObject(mGlobal);
// This initializes the state of the binary operator overload mechanism.
@ -712,7 +716,10 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
NewObject* no = static_cast<NewObject*>(instruction);
JSObject *obj = new JSObject();
(*registers)[dst(no).first] = new JSObject();
if (src1(no).first != NotARegister)
(*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]);
else
(*registers)[dst(no).first] = new JSObject();
}
break;
case NEW_CLASS:

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

@ -186,18 +186,23 @@ struct MathConstantEntry {
{ "SQRT1_2", M_SQRT1_2 }
};
JSMath::JSMath()
{
setClass(new JSString("Math"));
// There is no constructor for Math, we simply initialize
// the properties of the Math object
void JSMath::initMathObject(JSScope *g)
{
int i;
JSMath *m = new JSMath();
m->setClass(new JSString("Math"));
for (int i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (int i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
g->setProperty(widenCString("Math"), JSValue(m));
}
} /* JSMathClass */
} /* JavaScript */

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

@ -41,11 +41,13 @@ namespace JSMathClass {
using JSTypes::JSObject;
using JSTypes::JSString;
using JSTypes::JSScope;
class JSMath : public JSObject {
private:
JSMath() { }
public:
JSMath();
static void initMathObject(JSScope *g);
};

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

@ -55,17 +55,49 @@ JSValue object_toString(Context *cx, const JSValues& argv)
return kUndefinedValue;
}
JSValue objectConstructor(Context *cx, const JSValues& argv)
{
ASSERT(argv.size() > 0);
JSValue theThis = argv[0];
// the prototype and class have been established already
return theThis;
}
struct ObjectFunctionEntry {
char *name;
JSNativeFunction::JSCode fn;
} ObjectFunctions[] = {
{ "toString", object_toString },
};
JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject();
JSString *JSObject::ObjectString = new JSString("Object");
String JSObject::ObjectString = widenCString("Object");
// This establishes the ur-prototype, there's a timing issue
// here - the JSObject static initializers have to run before
// any other JSObject objects are constructed.
JSObject *JSObject::initJSObject()
{
JSObject *result = new JSObject();
result->setProperty(widenCString("toString"), JSValue(new JSNativeFunction(object_toString) ) );
for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++)
result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) );
return result;
}
// Install the 'Object' constructor into the scope, mostly irrelevant since making
// a new JSObject does all the work of setting the prototype and [[class]] values.
void JSObject::initObjectObject(JSScope *g)
{
JSObject* o = new JSObject();
g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor)));
}

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

@ -60,6 +60,7 @@ namespace JSTypes {
class JSObject;
class JSArray;
class JSFunction;
class JSScope;
class JSString;
class JSType;
class Context;
@ -224,12 +225,17 @@ namespace JSTypes {
JSType* mType;
JSString* mClass; // this is the internal [[Class]] property
public:
JSObject() : mPrototype(objectPrototypeObject), mType(&Any_Type), mClass(ObjectString) {}
static JSObject *objectPrototypeObject;
static JSObject *initJSObject();
static JSString *ObjectString;
static String ObjectString;
static JSObject *objectPrototypeObject;
void init(JSObject* prototype);
public:
JSObject() { init(objectPrototypeObject); }
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
static void initObjectObject(JSScope *g);
bool hasProperty(const String& name)
{
@ -551,6 +557,9 @@ namespace JSTypes {
};
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
} /* namespace JSTypes */
} /* namespace JavaScript */

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

@ -195,6 +195,10 @@ SOURCE=..\jsclasses.h
# End Source File
# Begin Source File
SOURCE=..\jsmath.h
# End Source File
# Begin Source File
SOURCE=..\jstypes.h
# End Source File
# Begin Source File

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

@ -235,6 +235,7 @@ static void readEvalPrint(FILE *in, World &world)
// list of zero or more statements
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
if (icm) {
stdOut << *icm;
JSValue result = cx.interpret(icm, JSValues());
stdOut << "result = " << result << "\n";
delete icm;

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

@ -128,9 +128,9 @@ $ops{"SAVE_NAME"} =
};
$ops{"NEW_OBJECT"} =
{
super => "Instruction_1",
rem => "dest",
params => [ ("TypedRegister") ]
super => "Instruction_2",
rem => "dest, constructor",
params => [ ("TypedRegister", "TypedRegister") ]
};
$ops{"NEW_CLASS"} =
{