mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Implemented Import -only it's not in the parser yet.
Added missing defineXXX functions.
This commit is contained in:
parent
91343cc3f0
commit
b8bd1adb30
@ -41,12 +41,18 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICG {
|
||||
|
||||
using namespace VM;
|
||||
using namespace JSTypes;
|
||||
using namespace JSClasses;
|
||||
using namespace Interpreter;
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
|
||||
uint32 ICodeModule::sMaxID = 0;
|
||||
|
||||
@ -206,7 +212,7 @@ TypedRegister ICodeGenerator::loadBoolean(bool value)
|
||||
return dest;
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::newObject(RegisterList */*args*/)
|
||||
TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/)
|
||||
{
|
||||
TypedRegister dest(getTempRegister(), &Any_Type);
|
||||
NewObject *instr = new NewObject(dest);
|
||||
@ -1117,7 +1123,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
case ExprNode::index :
|
||||
{
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
TypedRegister base = genExpr(b->op1);
|
||||
TypedRegister base = genExpr(b->op1);
|
||||
JSClass *clazz = dynamic_cast<JSClass*>(base.second);
|
||||
if (clazz) {
|
||||
// look for operator [] and invoke it
|
||||
}
|
||||
TypedRegister index = genExpr(b->op2);
|
||||
ret = getElement(base, index);
|
||||
}
|
||||
@ -1698,6 +1708,22 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::Import:
|
||||
{
|
||||
ImportStmtNode *i = static_cast<ImportStmtNode *>(p);
|
||||
String *fileName = i->bindings->packageName.str;
|
||||
if (fileName) { /// if not, build one from the idList instead
|
||||
std::string str(fileName->length(), char());
|
||||
std::transform(fileName->begin(), fileName->end(), str.begin(), narrow);
|
||||
FILE* f = fopen(str.c_str(), "r");
|
||||
if (f) {
|
||||
Context cx(*mWorld, mGlobal);
|
||||
JSValue result = cx.readEvalFile(f, *fileName);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::Var:
|
||||
{
|
||||
VariableStmtNode *vs = static_cast<VariableStmtNode *>(p);
|
||||
|
@ -114,6 +114,75 @@ struct Activation : public gc_base {
|
||||
|
||||
};
|
||||
|
||||
|
||||
JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
JSValues emptyArgs;
|
||||
JSValue result;
|
||||
|
||||
while (inReader.readLine(line) != 0) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
Arena a;
|
||||
Parser p(getWorld(), a, buffer, fileName);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||
{
|
||||
PrettyPrinter f(stdOut, 30);
|
||||
{
|
||||
PrettyPrinter::Block b(f, 2);
|
||||
f << "Program =";
|
||||
f.linearBreak(1);
|
||||
StmtNode::printStatements(f, parsedStatements);
|
||||
}
|
||||
f.end();
|
||||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(parsedStatements, fileName);
|
||||
if (icm) {
|
||||
result = interpret(icm, emptyArgs);
|
||||
delete icm;
|
||||
}
|
||||
|
||||
clear(buffer);
|
||||
} catch (Exception &e) {
|
||||
/* If we got a syntax error on the end of input,
|
||||
* then wait for a continuation
|
||||
* of input rather than printing the error message. */
|
||||
if (!(e.hasKind(Exception::syntaxError) &&
|
||||
e.lineNum && e.pos == buffer.size() &&
|
||||
e.sourceFile == fileName)) {
|
||||
stdOut << '\n' << e.fullMessage();
|
||||
clear(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
||||
{
|
||||
ICodeGenerator icg(&getWorld(), getGlobalObject());
|
||||
|
||||
TypedRegister ret(NotARegister, &None_Type);
|
||||
while (p) {
|
||||
ret = icg.genStmt(p);
|
||||
p = p->next;
|
||||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
||||
|
||||
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
|
||||
ICodeModule* Context::getICode() { return mActivation->mICode; }
|
||||
|
||||
@ -248,7 +317,7 @@ static JSValue less_Default(const JSValue& r1, const JSValue& r2)
|
||||
return JSValue(lv.f64 < rv.f64);
|
||||
}
|
||||
}
|
||||
static JSValue lessEqual_Default(const JSValue& r1, const JSValue& r2)
|
||||
static JSValue lessOrEqual_Default(const JSValue& r1, const JSValue& r2)
|
||||
{
|
||||
JSValue lv = r1.toPrimitive(JSValue::Number);
|
||||
JSValue rv = r2.toPrimitive(JSValue::Number);
|
||||
@ -314,7 +383,7 @@ public:
|
||||
typedef enum {
|
||||
Add, Subtract, Multiply, Divide,
|
||||
Remainder, LeftShift, RightShift, LogicalRightShift,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessEqual,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual,
|
||||
Equal, Identical
|
||||
} BinaryOp;
|
||||
|
||||
@ -349,7 +418,7 @@ BinaryOperator::BinaryOp BinaryOperator::mapICodeOp(ICodeOp op) {
|
||||
case XOR : return BitwiseXor;
|
||||
|
||||
case COMPARE_LT : return Less;
|
||||
case COMPARE_LE : return LessEqual;
|
||||
case COMPARE_LE : return LessOrEqual;
|
||||
case COMPARE_EQ : return Equal;
|
||||
case STRICT_EQ : return Identical;
|
||||
default :
|
||||
@ -377,7 +446,7 @@ JSBinaryOperator::JSBinaryCode defaultFunction[] = {
|
||||
xor_Default,
|
||||
and_Default,
|
||||
less_Default,
|
||||
lessEqual_Default,
|
||||
lessOrEqual_Default,
|
||||
equal_Default,
|
||||
identical_Default
|
||||
};
|
||||
@ -407,34 +476,88 @@ static JSValue defineAdd(const JSValues& argv)
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
#define DEFINE_OBO(NAME) \
|
||||
static JSValue define##NAME(const JSValues& argv) \
|
||||
{ \
|
||||
ASSERT(argv[0].isType()); \
|
||||
ASSERT(argv[1].isType()); \
|
||||
ASSERT(argv[2].isFunction()); \
|
||||
binaryOperators[BinaryOperator::##NAME].push_back( \
|
||||
new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \
|
||||
return kUndefinedValue; \
|
||||
} \
|
||||
|
||||
DEFINE_OBO(Subtract)
|
||||
DEFINE_OBO(Multiply)
|
||||
DEFINE_OBO(Divide)
|
||||
DEFINE_OBO(Remainder)
|
||||
DEFINE_OBO(LeftShift)
|
||||
DEFINE_OBO(RightShift)
|
||||
DEFINE_OBO(LogicalRightShift)
|
||||
DEFINE_OBO(BitwiseOr)
|
||||
DEFINE_OBO(BitwiseXor)
|
||||
DEFINE_OBO(BitwiseAnd)
|
||||
DEFINE_OBO(Less)
|
||||
DEFINE_OBO(LessOrEqual)
|
||||
DEFINE_OBO(Equal)
|
||||
DEFINE_OBO(Identical)
|
||||
|
||||
void Context::initContext()
|
||||
{
|
||||
// if global has a parent, assume it's been initialized already.
|
||||
if (mGlobal->getParent())
|
||||
return;
|
||||
|
||||
// predefine the predefined types;
|
||||
// predefine the umm, predefined types;
|
||||
struct PDT {
|
||||
char *name;
|
||||
JSType *type;
|
||||
} PDTs[] = {
|
||||
{ "any", &Any_Type },
|
||||
{ "Integer", &Integer_Type },
|
||||
{ "Number", &Number_Type },
|
||||
{ "Character", &Character_Type },
|
||||
{ "String", &String_Type },
|
||||
{ "Function", &Function_Type },
|
||||
{ "Array", &Array_Type },
|
||||
{ "Type", &Type_Type },
|
||||
{ "Boolean", &Boolean_Type },
|
||||
{ "Null", &Null_Type },
|
||||
{ "Void", &Void_Type },
|
||||
{ "none", &None_Type }
|
||||
};
|
||||
|
||||
mGlobal->defineVariable(widenCString("any"), &Type_Type, JSValue(&Any_Type));
|
||||
mGlobal->defineVariable(widenCString("Integer"), &Type_Type, JSValue(&Integer_Type));
|
||||
mGlobal->defineVariable(widenCString("Number"), &Type_Type, JSValue(&Number_Type));
|
||||
mGlobal->defineVariable(widenCString("Character"), &Type_Type, JSValue(&Character_Type));
|
||||
mGlobal->defineVariable(widenCString("String"), &Type_Type, JSValue(&String_Type));
|
||||
mGlobal->defineVariable(widenCString("Function"), &Type_Type, JSValue(&Function_Type));
|
||||
mGlobal->defineVariable(widenCString("Array"), &Type_Type, JSValue(&Array_Type));
|
||||
mGlobal->defineVariable(widenCString("Type"), &Type_Type, JSValue(&Type_Type));
|
||||
mGlobal->defineVariable(widenCString("Boolean"), &Type_Type, JSValue(&Boolean_Type));
|
||||
mGlobal->defineVariable(widenCString("Null"), &Type_Type, JSValue(&Null_Type));
|
||||
mGlobal->defineVariable(widenCString("Void"), &Type_Type, JSValue(&Void_Type));
|
||||
mGlobal->defineVariable(widenCString("none"), &Type_Type, JSValue(&None_Type));
|
||||
for (int i = 0; i < sizeof(PDTs) / sizeof(struct PDT); i++)
|
||||
mGlobal->defineVariable(widenCString(PDTs[i].name), &Type_Type, JSValue(PDTs[i].type));
|
||||
|
||||
|
||||
// hack - the following should be available only after importing the 'Operators' package
|
||||
// (hmm, how will that work - the import needs to connect the functions into this mechanism
|
||||
// do we watch for the specific package name???)
|
||||
|
||||
StringAtom& name = mWorld.identifiers[widenCString("defineAdd")];
|
||||
mGlobal->defineNativeFunction(name, defineAdd);
|
||||
struct OBO {
|
||||
char *name;
|
||||
JSValue (*fun)(const JSValues& argv);
|
||||
} OBOs[] = {
|
||||
{ "defineAdd", defineAdd },
|
||||
{ "defineSubtract", defineSubtract },
|
||||
{ "defineMultiply", defineMultiply },
|
||||
{ "defineDivide", defineDivide },
|
||||
{ "defineRemainder", defineRemainder },
|
||||
{ "defineLeftShift", defineLeftShift },
|
||||
{ "defineRightShift", defineRightShift },
|
||||
{ "defineLogicalRightShift",defineLogicalRightShift },
|
||||
{ "defineBitwiseOr", defineBitwiseOr },
|
||||
{ "defineBitwiseXor", defineBitwiseXor },
|
||||
{ "defineBitwiseAnd", defineBitwiseAnd },
|
||||
{ "defineLess", defineLess },
|
||||
{ "defineLessOrEqual", defineLessOrEqual },
|
||||
{ "defineEqual", defineEqual },
|
||||
{ "defineIdentical", defineIdentical },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++)
|
||||
mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun);
|
||||
}
|
||||
|
||||
static const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op)
|
||||
@ -918,6 +1041,11 @@ using JSString throughout.
|
||||
case COMPARE_EQ:
|
||||
case STRICT_EQ:
|
||||
{
|
||||
//
|
||||
// XXX if Package 'Operators' has not been seen, these operators cannot have been
|
||||
// overridden, so we should use a different dispatch and execute the default
|
||||
// behaviour inline instead,
|
||||
//
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
JSValue& dest = (*registers)[dst(mul).first];
|
||||
JSValue& r1 = (*registers)[src1(mul).first];
|
||||
|
@ -77,6 +77,10 @@ namespace Interpreter {
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
void doCall(JSFunction *target, Instruction *pc);
|
||||
|
||||
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
private:
|
||||
void broadcast(Event event);
|
||||
|
||||
|
@ -145,91 +145,28 @@ static JSValue dump(const JSValues &argv)
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
static ICodeModule* genCode(Context &cx, StmtNode *p, const String &fileName)
|
||||
{
|
||||
ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject());
|
||||
|
||||
TypedRegister ret(NotARegister, &None_Type);
|
||||
while (p) {
|
||||
ret = icg.genStmt(p);
|
||||
p = p->next;
|
||||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
||||
static JSValue readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
Context cx(world, &global);
|
||||
|
||||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
JSValues emptyArgs;
|
||||
JSValue result;
|
||||
|
||||
while (inReader.readLine(line) != 0) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
Arena a;
|
||||
Parser p(world, a, buffer, fileName);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||
{
|
||||
PrettyPrinter f(stdOut, 30);
|
||||
{
|
||||
PrettyPrinter::Block b(f, 2);
|
||||
f << "Program =";
|
||||
f.linearBreak(1);
|
||||
StmtNode::printStatements(f, parsedStatements);
|
||||
}
|
||||
f.end();
|
||||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(cx, parsedStatements, fileName);
|
||||
if (icm) {
|
||||
result = cx.interpret(icm, emptyArgs);
|
||||
delete icm;
|
||||
}
|
||||
|
||||
clear(buffer);
|
||||
} catch (Exception &e) {
|
||||
/* If we got a syntax error on the end of input,
|
||||
* then wait for a continuation
|
||||
* of input rather than printing the error message. */
|
||||
if (!(e.hasKind(Exception::syntaxError) &&
|
||||
e.lineNum && e.pos == buffer.size() &&
|
||||
e.sourceFile == fileName)) {
|
||||
stdOut << '\n' << e.fullMessage();
|
||||
clear(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
static JSValue load(const JSValues &argv)
|
||||
{
|
||||
|
||||
JSValue result;
|
||||
size_t n = argv.size();
|
||||
if (n > 1) { // the 'this' parameter is un-interesting
|
||||
if (n > 1) {
|
||||
ASSERT(argv[0].isObject());
|
||||
JSScope *scope = dynamic_cast<JSScope *>(argv[0].object);
|
||||
ASSERT(scope);
|
||||
for (size_t i = 1; i < n; ++i) {
|
||||
JSValue val = argv[i].toString();
|
||||
if (val.isString()) {
|
||||
Context cx(world, scope);
|
||||
String fileName(*val.string);
|
||||
std::string str(fileName.length(), char());
|
||||
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
|
||||
FILE* f = fopen(str.c_str(), "r");
|
||||
if (f) {
|
||||
result = readEvalFile(f, fileName);
|
||||
result = cx.readEvalFile(f, fileName);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
@ -288,7 +225,7 @@ static void readEvalPrint(FILE *in, World &world)
|
||||
#endif
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(cx, parsedStatements, ConsoleName);
|
||||
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
|
||||
if (icm) {
|
||||
JSValue result = cx.interpret(icm, JSValues());
|
||||
stdOut << "result = " << result << "\n";
|
||||
|
@ -103,7 +103,16 @@ const JSType *JSValue::getType() const
|
||||
case JSValue::f64_tag:
|
||||
return &Number_Type;
|
||||
case JSValue::object_tag:
|
||||
return &Any_Type; // XXX get type from Object
|
||||
{
|
||||
//
|
||||
// XXX why isn't there a class for Object? XXX
|
||||
//
|
||||
JSClass *clazz = dynamic_cast<JSClass *>(object->getType());
|
||||
if (clazz)
|
||||
return clazz;
|
||||
else
|
||||
return &Any_Type;
|
||||
}
|
||||
case JSValue::array_tag:
|
||||
return &Array_Type;
|
||||
case JSValue::function_tag:
|
||||
|
@ -41,12 +41,18 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
|
||||
namespace JavaScript {
|
||||
namespace ICG {
|
||||
|
||||
using namespace VM;
|
||||
using namespace JSTypes;
|
||||
using namespace JSClasses;
|
||||
using namespace Interpreter;
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
|
||||
uint32 ICodeModule::sMaxID = 0;
|
||||
|
||||
@ -206,7 +212,7 @@ TypedRegister ICodeGenerator::loadBoolean(bool value)
|
||||
return dest;
|
||||
}
|
||||
|
||||
TypedRegister ICodeGenerator::newObject(RegisterList */*args*/)
|
||||
TypedRegister ICodeGenerator::newObject(RegisterList * /*args*/)
|
||||
{
|
||||
TypedRegister dest(getTempRegister(), &Any_Type);
|
||||
NewObject *instr = new NewObject(dest);
|
||||
@ -1117,7 +1123,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
|
||||
case ExprNode::index :
|
||||
{
|
||||
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
|
||||
TypedRegister base = genExpr(b->op1);
|
||||
TypedRegister base = genExpr(b->op1);
|
||||
JSClass *clazz = dynamic_cast<JSClass*>(base.second);
|
||||
if (clazz) {
|
||||
// look for operator [] and invoke it
|
||||
}
|
||||
TypedRegister index = genExpr(b->op2);
|
||||
ret = getElement(base, index);
|
||||
}
|
||||
@ -1698,6 +1708,22 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::Import:
|
||||
{
|
||||
ImportStmtNode *i = static_cast<ImportStmtNode *>(p);
|
||||
String *fileName = i->bindings->packageName.str;
|
||||
if (fileName) { /// if not, build one from the idList instead
|
||||
std::string str(fileName->length(), char());
|
||||
std::transform(fileName->begin(), fileName->end(), str.begin(), narrow);
|
||||
FILE* f = fopen(str.c_str(), "r");
|
||||
if (f) {
|
||||
Context cx(*mWorld, mGlobal);
|
||||
JSValue result = cx.readEvalFile(f, *fileName);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::Var:
|
||||
{
|
||||
VariableStmtNode *vs = static_cast<VariableStmtNode *>(p);
|
||||
|
@ -114,6 +114,75 @@ struct Activation : public gc_base {
|
||||
|
||||
};
|
||||
|
||||
|
||||
JSValue Context::readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
JSValues emptyArgs;
|
||||
JSValue result;
|
||||
|
||||
while (inReader.readLine(line) != 0) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
Arena a;
|
||||
Parser p(getWorld(), a, buffer, fileName);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||
{
|
||||
PrettyPrinter f(stdOut, 30);
|
||||
{
|
||||
PrettyPrinter::Block b(f, 2);
|
||||
f << "Program =";
|
||||
f.linearBreak(1);
|
||||
StmtNode::printStatements(f, parsedStatements);
|
||||
}
|
||||
f.end();
|
||||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(parsedStatements, fileName);
|
||||
if (icm) {
|
||||
result = interpret(icm, emptyArgs);
|
||||
delete icm;
|
||||
}
|
||||
|
||||
clear(buffer);
|
||||
} catch (Exception &e) {
|
||||
/* If we got a syntax error on the end of input,
|
||||
* then wait for a continuation
|
||||
* of input rather than printing the error message. */
|
||||
if (!(e.hasKind(Exception::syntaxError) &&
|
||||
e.lineNum && e.pos == buffer.size() &&
|
||||
e.sourceFile == fileName)) {
|
||||
stdOut << '\n' << e.fullMessage();
|
||||
clear(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
||||
{
|
||||
ICodeGenerator icg(&getWorld(), getGlobalObject());
|
||||
|
||||
TypedRegister ret(NotARegister, &None_Type);
|
||||
while (p) {
|
||||
ret = icg.genStmt(p);
|
||||
p = p->next;
|
||||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
||||
|
||||
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
|
||||
ICodeModule* Context::getICode() { return mActivation->mICode; }
|
||||
|
||||
@ -248,7 +317,7 @@ static JSValue less_Default(const JSValue& r1, const JSValue& r2)
|
||||
return JSValue(lv.f64 < rv.f64);
|
||||
}
|
||||
}
|
||||
static JSValue lessEqual_Default(const JSValue& r1, const JSValue& r2)
|
||||
static JSValue lessOrEqual_Default(const JSValue& r1, const JSValue& r2)
|
||||
{
|
||||
JSValue lv = r1.toPrimitive(JSValue::Number);
|
||||
JSValue rv = r2.toPrimitive(JSValue::Number);
|
||||
@ -314,7 +383,7 @@ public:
|
||||
typedef enum {
|
||||
Add, Subtract, Multiply, Divide,
|
||||
Remainder, LeftShift, RightShift, LogicalRightShift,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessEqual,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual,
|
||||
Equal, Identical
|
||||
} BinaryOp;
|
||||
|
||||
@ -349,7 +418,7 @@ BinaryOperator::BinaryOp BinaryOperator::mapICodeOp(ICodeOp op) {
|
||||
case XOR : return BitwiseXor;
|
||||
|
||||
case COMPARE_LT : return Less;
|
||||
case COMPARE_LE : return LessEqual;
|
||||
case COMPARE_LE : return LessOrEqual;
|
||||
case COMPARE_EQ : return Equal;
|
||||
case STRICT_EQ : return Identical;
|
||||
default :
|
||||
@ -377,7 +446,7 @@ JSBinaryOperator::JSBinaryCode defaultFunction[] = {
|
||||
xor_Default,
|
||||
and_Default,
|
||||
less_Default,
|
||||
lessEqual_Default,
|
||||
lessOrEqual_Default,
|
||||
equal_Default,
|
||||
identical_Default
|
||||
};
|
||||
@ -407,34 +476,88 @@ static JSValue defineAdd(const JSValues& argv)
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
#define DEFINE_OBO(NAME) \
|
||||
static JSValue define##NAME(const JSValues& argv) \
|
||||
{ \
|
||||
ASSERT(argv[0].isType()); \
|
||||
ASSERT(argv[1].isType()); \
|
||||
ASSERT(argv[2].isFunction()); \
|
||||
binaryOperators[BinaryOperator::##NAME].push_back( \
|
||||
new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \
|
||||
return kUndefinedValue; \
|
||||
} \
|
||||
|
||||
DEFINE_OBO(Subtract)
|
||||
DEFINE_OBO(Multiply)
|
||||
DEFINE_OBO(Divide)
|
||||
DEFINE_OBO(Remainder)
|
||||
DEFINE_OBO(LeftShift)
|
||||
DEFINE_OBO(RightShift)
|
||||
DEFINE_OBO(LogicalRightShift)
|
||||
DEFINE_OBO(BitwiseOr)
|
||||
DEFINE_OBO(BitwiseXor)
|
||||
DEFINE_OBO(BitwiseAnd)
|
||||
DEFINE_OBO(Less)
|
||||
DEFINE_OBO(LessOrEqual)
|
||||
DEFINE_OBO(Equal)
|
||||
DEFINE_OBO(Identical)
|
||||
|
||||
void Context::initContext()
|
||||
{
|
||||
// if global has a parent, assume it's been initialized already.
|
||||
if (mGlobal->getParent())
|
||||
return;
|
||||
|
||||
// predefine the predefined types;
|
||||
// predefine the umm, predefined types;
|
||||
struct PDT {
|
||||
char *name;
|
||||
JSType *type;
|
||||
} PDTs[] = {
|
||||
{ "any", &Any_Type },
|
||||
{ "Integer", &Integer_Type },
|
||||
{ "Number", &Number_Type },
|
||||
{ "Character", &Character_Type },
|
||||
{ "String", &String_Type },
|
||||
{ "Function", &Function_Type },
|
||||
{ "Array", &Array_Type },
|
||||
{ "Type", &Type_Type },
|
||||
{ "Boolean", &Boolean_Type },
|
||||
{ "Null", &Null_Type },
|
||||
{ "Void", &Void_Type },
|
||||
{ "none", &None_Type }
|
||||
};
|
||||
|
||||
mGlobal->defineVariable(widenCString("any"), &Type_Type, JSValue(&Any_Type));
|
||||
mGlobal->defineVariable(widenCString("Integer"), &Type_Type, JSValue(&Integer_Type));
|
||||
mGlobal->defineVariable(widenCString("Number"), &Type_Type, JSValue(&Number_Type));
|
||||
mGlobal->defineVariable(widenCString("Character"), &Type_Type, JSValue(&Character_Type));
|
||||
mGlobal->defineVariable(widenCString("String"), &Type_Type, JSValue(&String_Type));
|
||||
mGlobal->defineVariable(widenCString("Function"), &Type_Type, JSValue(&Function_Type));
|
||||
mGlobal->defineVariable(widenCString("Array"), &Type_Type, JSValue(&Array_Type));
|
||||
mGlobal->defineVariable(widenCString("Type"), &Type_Type, JSValue(&Type_Type));
|
||||
mGlobal->defineVariable(widenCString("Boolean"), &Type_Type, JSValue(&Boolean_Type));
|
||||
mGlobal->defineVariable(widenCString("Null"), &Type_Type, JSValue(&Null_Type));
|
||||
mGlobal->defineVariable(widenCString("Void"), &Type_Type, JSValue(&Void_Type));
|
||||
mGlobal->defineVariable(widenCString("none"), &Type_Type, JSValue(&None_Type));
|
||||
for (int i = 0; i < sizeof(PDTs) / sizeof(struct PDT); i++)
|
||||
mGlobal->defineVariable(widenCString(PDTs[i].name), &Type_Type, JSValue(PDTs[i].type));
|
||||
|
||||
|
||||
// hack - the following should be available only after importing the 'Operators' package
|
||||
// (hmm, how will that work - the import needs to connect the functions into this mechanism
|
||||
// do we watch for the specific package name???)
|
||||
|
||||
StringAtom& name = mWorld.identifiers[widenCString("defineAdd")];
|
||||
mGlobal->defineNativeFunction(name, defineAdd);
|
||||
struct OBO {
|
||||
char *name;
|
||||
JSValue (*fun)(const JSValues& argv);
|
||||
} OBOs[] = {
|
||||
{ "defineAdd", defineAdd },
|
||||
{ "defineSubtract", defineSubtract },
|
||||
{ "defineMultiply", defineMultiply },
|
||||
{ "defineDivide", defineDivide },
|
||||
{ "defineRemainder", defineRemainder },
|
||||
{ "defineLeftShift", defineLeftShift },
|
||||
{ "defineRightShift", defineRightShift },
|
||||
{ "defineLogicalRightShift",defineLogicalRightShift },
|
||||
{ "defineBitwiseOr", defineBitwiseOr },
|
||||
{ "defineBitwiseXor", defineBitwiseXor },
|
||||
{ "defineBitwiseAnd", defineBitwiseAnd },
|
||||
{ "defineLess", defineLess },
|
||||
{ "defineLessOrEqual", defineLessOrEqual },
|
||||
{ "defineEqual", defineEqual },
|
||||
{ "defineIdentical", defineIdentical },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++)
|
||||
mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun);
|
||||
}
|
||||
|
||||
static const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op)
|
||||
@ -918,6 +1041,11 @@ using JSString throughout.
|
||||
case COMPARE_EQ:
|
||||
case STRICT_EQ:
|
||||
{
|
||||
//
|
||||
// XXX if Package 'Operators' has not been seen, these operators cannot have been
|
||||
// overridden, so we should use a different dispatch and execute the default
|
||||
// behaviour inline instead,
|
||||
//
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
JSValue& dest = (*registers)[dst(mul).first];
|
||||
JSValue& r1 = (*registers)[src1(mul).first];
|
||||
|
@ -77,6 +77,10 @@ namespace Interpreter {
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
void doCall(JSFunction *target, Instruction *pc);
|
||||
|
||||
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
private:
|
||||
void broadcast(Event event);
|
||||
|
||||
|
@ -103,7 +103,16 @@ const JSType *JSValue::getType() const
|
||||
case JSValue::f64_tag:
|
||||
return &Number_Type;
|
||||
case JSValue::object_tag:
|
||||
return &Any_Type; // XXX get type from Object
|
||||
{
|
||||
//
|
||||
// XXX why isn't there a class for Object? XXX
|
||||
//
|
||||
JSClass *clazz = dynamic_cast<JSClass *>(object->getType());
|
||||
if (clazz)
|
||||
return clazz;
|
||||
else
|
||||
return &Any_Type;
|
||||
}
|
||||
case JSValue::array_tag:
|
||||
return &Array_Type;
|
||||
case JSValue::function_tag:
|
||||
|
@ -145,91 +145,28 @@ static JSValue dump(const JSValues &argv)
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
static ICodeModule* genCode(Context &cx, StmtNode *p, const String &fileName)
|
||||
{
|
||||
ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject());
|
||||
|
||||
TypedRegister ret(NotARegister, &None_Type);
|
||||
while (p) {
|
||||
ret = icg.genStmt(p);
|
||||
p = p->next;
|
||||
}
|
||||
icg.returnStmt(ret);
|
||||
|
||||
ICodeModule *icm = icg.complete();
|
||||
icm->setFileName (fileName);
|
||||
return icm;
|
||||
}
|
||||
|
||||
static JSValue readEvalFile(FILE* in, const String& fileName)
|
||||
{
|
||||
Context cx(world, &global);
|
||||
|
||||
String buffer;
|
||||
string line;
|
||||
LineReader inReader(in);
|
||||
JSValues emptyArgs;
|
||||
JSValue result;
|
||||
|
||||
while (inReader.readLine(line) != 0) {
|
||||
appendChars(buffer, line.data(), line.size());
|
||||
try {
|
||||
Arena a;
|
||||
Parser p(world, a, buffer, fileName);
|
||||
StmtNode *parsedStatements = p.parseProgram();
|
||||
ASSERT(p.lexer.peek(true).hasKind(Token::end));
|
||||
{
|
||||
PrettyPrinter f(stdOut, 30);
|
||||
{
|
||||
PrettyPrinter::Block b(f, 2);
|
||||
f << "Program =";
|
||||
f.linearBreak(1);
|
||||
StmtNode::printStatements(f, parsedStatements);
|
||||
}
|
||||
f.end();
|
||||
}
|
||||
stdOut << '\n';
|
||||
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(cx, parsedStatements, fileName);
|
||||
if (icm) {
|
||||
result = cx.interpret(icm, emptyArgs);
|
||||
delete icm;
|
||||
}
|
||||
|
||||
clear(buffer);
|
||||
} catch (Exception &e) {
|
||||
/* If we got a syntax error on the end of input,
|
||||
* then wait for a continuation
|
||||
* of input rather than printing the error message. */
|
||||
if (!(e.hasKind(Exception::syntaxError) &&
|
||||
e.lineNum && e.pos == buffer.size() &&
|
||||
e.sourceFile == fileName)) {
|
||||
stdOut << '\n' << e.fullMessage();
|
||||
clear(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline char narrow(char16 ch) { return char(ch); }
|
||||
|
||||
static JSValue load(const JSValues &argv)
|
||||
{
|
||||
|
||||
JSValue result;
|
||||
size_t n = argv.size();
|
||||
if (n > 1) { // the 'this' parameter is un-interesting
|
||||
if (n > 1) {
|
||||
ASSERT(argv[0].isObject());
|
||||
JSScope *scope = dynamic_cast<JSScope *>(argv[0].object);
|
||||
ASSERT(scope);
|
||||
for (size_t i = 1; i < n; ++i) {
|
||||
JSValue val = argv[i].toString();
|
||||
if (val.isString()) {
|
||||
Context cx(world, scope);
|
||||
String fileName(*val.string);
|
||||
std::string str(fileName.length(), char());
|
||||
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
|
||||
FILE* f = fopen(str.c_str(), "r");
|
||||
if (f) {
|
||||
result = readEvalFile(f, fileName);
|
||||
result = cx.readEvalFile(f, fileName);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
@ -288,7 +225,7 @@ static void readEvalPrint(FILE *in, World &world)
|
||||
#endif
|
||||
// Generate code for parsedStatements, which is a linked
|
||||
// list of zero or more statements
|
||||
ICodeModule* icm = genCode(cx, parsedStatements, ConsoleName);
|
||||
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
|
||||
if (icm) {
|
||||
JSValue result = cx.interpret(icm, JSValues());
|
||||
stdOut << "result = " << result << "\n";
|
||||
|
Loading…
Reference in New Issue
Block a user