Function prototype objects etc.

This commit is contained in:
rogerl%netscape.com 2000-07-26 01:56:47 +00:00
Родитель 7106be3510
Коммит 9cb37bc8c8
12 изменённых файлов: 220 добавлений и 18 удалений

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

@ -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;