зеркало из https://github.com/mozilla/gecko-dev.git
Function prototype objects etc.
This commit is contained in:
Родитель
7106be3510
Коммит
9cb37bc8c8
|
@ -1100,7 +1100,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
JSClass* clazz = dynamic_cast<JSClass*>(value.type);
|
||||
if (clazz) {
|
||||
ret = newClass(clazz);
|
||||
call(getStatic(clazz, className), ret, &args);
|
||||
ret = call(getStatic(clazz, className), ret, &args);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("new <name>, where <name> is not a new-able type (whatever that means)"); // XXX Runtime error.
|
||||
|
@ -1109,7 +1109,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
if (value.isFunction()) {
|
||||
TypedRegister f = loadName(className, value.type);
|
||||
ret = newObject(f);
|
||||
call(f, ret, &args);
|
||||
ret = call(f, ret, &args);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("new <name>, where <name> is not a function"); // XXX Runtime error.
|
||||
|
@ -1695,7 +1695,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
else
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("unimplemented class member statement");
|
||||
|
@ -1712,9 +1712,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
RegisterList args;
|
||||
ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args);
|
||||
icg.call(icg.getStatic(thisClass, initName), thisValue, &args);
|
||||
icg.returnStmt(thisValue);
|
||||
thisClass->defineConstructor(nameExpr->name);
|
||||
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete()));
|
||||
}
|
||||
|
|
|
@ -129,6 +129,15 @@ public:
|
|||
~autosaver() { mRef = mOld; }
|
||||
};
|
||||
|
||||
ICodeModule* Context::compile(const String &source)
|
||||
{
|
||||
Arena a;
|
||||
String filename = widenCString("Some source source");
|
||||
Parser p(getWorld(), a, source, filename);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
return genCode(parsedStatements, filename);
|
||||
}
|
||||
|
||||
JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
String buffer;
|
||||
|
@ -162,7 +171,7 @@ JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
|||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(parsedStatements, fileName);
|
||||
if (icm) {
|
||||
|
@ -508,6 +517,7 @@ void Context::initContext()
|
|||
|
||||
// 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object
|
||||
JSObject::initObjectObject(mGlobal);
|
||||
JSFunction::initFunctionObject(mGlobal);
|
||||
|
||||
// the 'Math' object just has some useful properties
|
||||
JSMath::initMathObject(mGlobal);
|
||||
|
@ -715,7 +725,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
JSObject *obj = new JSObject();
|
||||
if (src1(no).first != NotARegister)
|
||||
(*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]);
|
||||
else
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace Interpreter {
|
|||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
void doCall(JSFunction *target, Instruction *pc);
|
||||
|
||||
ICodeModule* compile(const String &source);
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
|
|
|
@ -303,7 +303,6 @@ static void testCompile()
|
|||
JSScope glob;
|
||||
Context cx(world, &glob);
|
||||
glob.defineNativeFunction(world.identifiers["print"], print);
|
||||
|
||||
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
|
||||
String testScript = widenCString(tests[i]);
|
||||
Arena a;
|
||||
|
|
|
@ -35,12 +35,15 @@
|
|||
#include "jsclasses.h"
|
||||
#include "numerics.h"
|
||||
#include "icodegenerator.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
|
||||
using namespace JSClasses;
|
||||
using namespace Interpreter;
|
||||
|
||||
/********** Object Object Stuff **************************/
|
||||
|
||||
JSValue object_toString(Context *cx, const JSValues& argv)
|
||||
{
|
||||
|
@ -93,14 +96,94 @@ JSObject *JSObject::initJSObject()
|
|||
// a new JSObject does all the work of setting the prototype and [[class]] values.
|
||||
void JSObject::initObjectObject(JSScope *g)
|
||||
{
|
||||
JSObject* o = new JSObject();
|
||||
JSNativeFunction *objCon = new JSNativeFunction(objectConstructor);
|
||||
|
||||
g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor)));
|
||||
objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject));
|
||||
|
||||
|
||||
|
||||
|
||||
g->setProperty(ObjectString, JSValue(objCon));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********** Function Object Stuff **************************/
|
||||
|
||||
// An empty function that returns undefined
|
||||
JSValue functionPrototypeFunction(Context *cx, const JSValues& argv)
|
||||
{
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
|
||||
JSValue function_constructor(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// build a function from the arguments into the this.
|
||||
ASSERT(argv.size() > 0);
|
||||
JSValue theThis = argv[0];
|
||||
ASSERT(theThis.isObject());
|
||||
|
||||
if (argv.size() == 2) {
|
||||
JSValue s = JSValue::valueToString(argv[1]);
|
||||
theThis = new JSFunction(cx->compile((String)(*s.string)));
|
||||
}
|
||||
|
||||
return theThis;
|
||||
}
|
||||
|
||||
JSValue function_toString(Context *cx, const JSValues& argv)
|
||||
{
|
||||
return JSValue(new JSString("function XXX() { }" ));
|
||||
}
|
||||
JSValue function_apply(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// XXX
|
||||
return kUndefinedValue;
|
||||
}
|
||||
JSValue function_call(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// XXX
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String JSFunction::FunctionString = widenCString("Function");
|
||||
JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object'
|
||||
|
||||
struct FunctionFunctionEntry {
|
||||
char *name;
|
||||
JSNativeFunction::JSCode fn;
|
||||
} FunctionFunctions[] = {
|
||||
{ "constructor", function_constructor },
|
||||
{ "toString", function_toString },
|
||||
{ "apply", function_apply },
|
||||
{ "call", function_call },
|
||||
};
|
||||
|
||||
void JSFunction::initFunctionObject(JSScope *g)
|
||||
{
|
||||
// first build the Function Prototype Object
|
||||
functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction);
|
||||
for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++)
|
||||
functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) );
|
||||
|
||||
// now the Function Constructor Object
|
||||
JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor);
|
||||
functionConstructorObject->setPrototype(functionPrototypeObject);
|
||||
functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1));
|
||||
functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject));
|
||||
|
||||
// This is interesting - had to use defineVariable here to specify a type because
|
||||
// when left as Any_Type (via setProperty), the Function predefined type interacted
|
||||
// badly with this value. (I think setProperty perhaps should have reset the entry
|
||||
// in mTypes) (?)
|
||||
g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject));
|
||||
}
|
||||
|
||||
/**************************************************************************************/
|
||||
|
||||
JSType Any_Type = JSType(widenCString("any"), NULL);
|
||||
JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type);
|
||||
JSType Number_Type = JSType(widenCString("Number"), &Integer_Type);
|
||||
|
|
|
@ -234,6 +234,7 @@ namespace JSTypes {
|
|||
public:
|
||||
JSObject() { init(objectPrototypeObject); }
|
||||
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
|
||||
JSObject(JSObject *prototype) { init(prototype); }
|
||||
|
||||
static void initObjectObject(JSScope *g);
|
||||
|
||||
|
@ -367,6 +368,8 @@ namespace JSTypes {
|
|||
* compiled code of the function.
|
||||
*/
|
||||
class JSFunction : public JSObject {
|
||||
static String FunctionString;
|
||||
static JSObject *functionPrototypeObject;
|
||||
ICodeModule* mICode;
|
||||
protected:
|
||||
JSFunction() : mICode(0) {}
|
||||
|
@ -375,7 +378,9 @@ namespace JSTypes {
|
|||
typedef gc_allocator<JSFunction, traits> allocator;
|
||||
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
static void JSFunction::initFunctionObject(JSScope *g);
|
||||
|
||||
JSFunction(ICodeModule* iCode);
|
||||
~JSFunction();
|
||||
|
||||
void* operator new(size_t) { return allocator::allocate(1); }
|
||||
|
@ -558,6 +563,8 @@ namespace JSTypes {
|
|||
|
||||
|
||||
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
|
||||
|
||||
inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); }
|
||||
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
|
|
@ -1100,7 +1100,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
JSClass* clazz = dynamic_cast<JSClass*>(value.type);
|
||||
if (clazz) {
|
||||
ret = newClass(clazz);
|
||||
call(getStatic(clazz, className), ret, &args);
|
||||
ret = call(getStatic(clazz, className), ret, &args);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("new <name>, where <name> is not a new-able type (whatever that means)"); // XXX Runtime error.
|
||||
|
@ -1109,7 +1109,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
|||
if (value.isFunction()) {
|
||||
TypedRegister f = loadName(className, value.type);
|
||||
ret = newObject(f);
|
||||
call(f, ret, &args);
|
||||
ret = call(f, ret, &args);
|
||||
}
|
||||
else
|
||||
NOT_REACHED("new <name>, where <name> is not a function"); // XXX Runtime error.
|
||||
|
@ -1695,7 +1695,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
else
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("unimplemented class member statement");
|
||||
|
@ -1712,9 +1712,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
|||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
RegisterList args;
|
||||
ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod);
|
||||
icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
|
||||
if (superclass)
|
||||
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args);
|
||||
icg.call(icg.getStatic(thisClass, initName), thisValue, &args);
|
||||
icg.returnStmt(thisValue);
|
||||
thisClass->defineConstructor(nameExpr->name);
|
||||
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete()));
|
||||
}
|
||||
|
|
|
@ -129,6 +129,15 @@ public:
|
|||
~autosaver() { mRef = mOld; }
|
||||
};
|
||||
|
||||
ICodeModule* Context::compile(const String &source)
|
||||
{
|
||||
Arena a;
|
||||
String filename = widenCString("Some source source");
|
||||
Parser p(getWorld(), a, source, filename);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
return genCode(parsedStatements, filename);
|
||||
}
|
||||
|
||||
JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
String buffer;
|
||||
|
@ -162,7 +171,7 @@ JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
|||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(parsedStatements, fileName);
|
||||
if (icm) {
|
||||
|
@ -508,6 +517,7 @@ void Context::initContext()
|
|||
|
||||
// 'Object', 'Date', 'RegExp', 'Array' etc are all (constructor) properties of the global object
|
||||
JSObject::initObjectObject(mGlobal);
|
||||
JSFunction::initFunctionObject(mGlobal);
|
||||
|
||||
// the 'Math' object just has some useful properties
|
||||
JSMath::initMathObject(mGlobal);
|
||||
|
@ -715,7 +725,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
|||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
JSObject *obj = new JSObject();
|
||||
if (src1(no).first != NotARegister)
|
||||
(*registers)[dst(no).first] = new JSObject((*registers)[src1(no).first]);
|
||||
else
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace Interpreter {
|
|||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
void doCall(JSFunction *target, Instruction *pc);
|
||||
|
||||
ICodeModule* compile(const String &source);
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
|
|
|
@ -35,12 +35,15 @@
|
|||
#include "jsclasses.h"
|
||||
#include "numerics.h"
|
||||
#include "icodegenerator.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
namespace JavaScript {
|
||||
namespace JSTypes {
|
||||
|
||||
using namespace JSClasses;
|
||||
using namespace Interpreter;
|
||||
|
||||
/********** Object Object Stuff **************************/
|
||||
|
||||
JSValue object_toString(Context *cx, const JSValues& argv)
|
||||
{
|
||||
|
@ -93,14 +96,94 @@ JSObject *JSObject::initJSObject()
|
|||
// a new JSObject does all the work of setting the prototype and [[class]] values.
|
||||
void JSObject::initObjectObject(JSScope *g)
|
||||
{
|
||||
JSObject* o = new JSObject();
|
||||
JSNativeFunction *objCon = new JSNativeFunction(objectConstructor);
|
||||
|
||||
g->setProperty(ObjectString, JSValue(new JSNativeFunction(objectConstructor)));
|
||||
objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject));
|
||||
|
||||
|
||||
|
||||
|
||||
g->setProperty(ObjectString, JSValue(objCon));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********** Function Object Stuff **************************/
|
||||
|
||||
// An empty function that returns undefined
|
||||
JSValue functionPrototypeFunction(Context *cx, const JSValues& argv)
|
||||
{
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
|
||||
JSValue function_constructor(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// build a function from the arguments into the this.
|
||||
ASSERT(argv.size() > 0);
|
||||
JSValue theThis = argv[0];
|
||||
ASSERT(theThis.isObject());
|
||||
|
||||
if (argv.size() == 2) {
|
||||
JSValue s = JSValue::valueToString(argv[1]);
|
||||
theThis = new JSFunction(cx->compile((String)(*s.string)));
|
||||
}
|
||||
|
||||
return theThis;
|
||||
}
|
||||
|
||||
JSValue function_toString(Context *cx, const JSValues& argv)
|
||||
{
|
||||
return JSValue(new JSString("function XXX() { }" ));
|
||||
}
|
||||
JSValue function_apply(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// XXX
|
||||
return kUndefinedValue;
|
||||
}
|
||||
JSValue function_call(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// XXX
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String JSFunction::FunctionString = widenCString("Function");
|
||||
JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object'
|
||||
|
||||
struct FunctionFunctionEntry {
|
||||
char *name;
|
||||
JSNativeFunction::JSCode fn;
|
||||
} FunctionFunctions[] = {
|
||||
{ "constructor", function_constructor },
|
||||
{ "toString", function_toString },
|
||||
{ "apply", function_apply },
|
||||
{ "call", function_call },
|
||||
};
|
||||
|
||||
void JSFunction::initFunctionObject(JSScope *g)
|
||||
{
|
||||
// first build the Function Prototype Object
|
||||
functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction);
|
||||
for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++)
|
||||
functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) );
|
||||
|
||||
// now the Function Constructor Object
|
||||
JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor);
|
||||
functionConstructorObject->setPrototype(functionPrototypeObject);
|
||||
functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1));
|
||||
functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject));
|
||||
|
||||
// This is interesting - had to use defineVariable here to specify a type because
|
||||
// when left as Any_Type (via setProperty), the Function predefined type interacted
|
||||
// badly with this value. (I think setProperty perhaps should have reset the entry
|
||||
// in mTypes) (?)
|
||||
g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject));
|
||||
}
|
||||
|
||||
/**************************************************************************************/
|
||||
|
||||
JSType Any_Type = JSType(widenCString("any"), NULL);
|
||||
JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type);
|
||||
JSType Number_Type = JSType(widenCString("Number"), &Integer_Type);
|
||||
|
|
|
@ -234,6 +234,7 @@ namespace JSTypes {
|
|||
public:
|
||||
JSObject() { init(objectPrototypeObject); }
|
||||
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
|
||||
JSObject(JSObject *prototype) { init(prototype); }
|
||||
|
||||
static void initObjectObject(JSScope *g);
|
||||
|
||||
|
@ -367,6 +368,8 @@ namespace JSTypes {
|
|||
* compiled code of the function.
|
||||
*/
|
||||
class JSFunction : public JSObject {
|
||||
static String FunctionString;
|
||||
static JSObject *functionPrototypeObject;
|
||||
ICodeModule* mICode;
|
||||
protected:
|
||||
JSFunction() : mICode(0) {}
|
||||
|
@ -375,7 +378,9 @@ namespace JSTypes {
|
|||
typedef gc_allocator<JSFunction, traits> allocator;
|
||||
|
||||
public:
|
||||
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
|
||||
static void JSFunction::initFunctionObject(JSScope *g);
|
||||
|
||||
JSFunction(ICodeModule* iCode);
|
||||
~JSFunction();
|
||||
|
||||
void* operator new(size_t) { return allocator::allocate(1); }
|
||||
|
@ -558,6 +563,8 @@ namespace JSTypes {
|
|||
|
||||
|
||||
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
|
||||
|
||||
inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); }
|
||||
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
|
|
@ -303,7 +303,6 @@ static void testCompile()
|
|||
JSScope glob;
|
||||
Context cx(world, &glob);
|
||||
glob.defineNativeFunction(world.identifiers["print"], print);
|
||||
|
||||
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
|
||||
String testScript = widenCString(tests[i]);
|
||||
Arena a;
|
||||
|
|
Загрузка…
Ссылка в новой задаче