Added XMLparsing to load a class. Fixed handling of forward references to

class methods/fields.
This commit is contained in:
rogerl%netscape.com 2000-10-18 23:37:44 +00:00
Родитель 8a620cdea1
Коммит 7806a764aa
16 изменённых файлов: 1208 добавлений и 74 удалений

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

@ -38,6 +38,8 @@
#include "jsclasses.h"
#include "icodegenerator.h"
#include "interpreter.h"
#include "xmlparser.h"
#include "icodeasm.h"
#include <stdexcept>
#include <stdio.h>
@ -49,6 +51,7 @@ using namespace VM;
using namespace JSTypes;
using namespace JSClasses;
using namespace Interpreter;
using namespace ICodeASM;
inline char narrow(char16 ch) { return char(ch); }
@ -82,7 +85,8 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I
mFlags(flags),
pLabels(NULL),
mHasRestParameter(false),
mHasNamedRestParameter(false)
mHasNamedRestParameter(false),
mInitName(world->identifiers["__init__"])
{
iCode = new InstructionStream();
iCodeOwner = true;
@ -1724,8 +1728,9 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args);
}
}
const StringAtom &initName = mWorld->identifiers["__init__"]; // XXXXXXX
icg.call(icg.getStatic(mClass, initName), thisValue, &args); // ok, so it's mis-named
if (mClass->hasStatic(mInitName))
icg.call(icg.getStatic(mClass, mInitName), thisValue, &args); // ok, so it's mis-named
}
if (f->function.body)
icg.genStmt(f->function.body);
@ -1765,48 +1770,118 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
// to handle recursive types, such as linked list nodes.
mGlobal->defineVariable(nameExpr->name, &Type_Type, JSValue(thisClass));
// Have to have this declared ahead of time so that it's slot can
// be discoverd when compiling constructors in the loop below. Could
// do a pre-processing loop to discover whether it is in fact empty
// and then pass that info through to the genFunction() call for each
// constructor.
const StringAtom &initName = mWorld->identifiers["__init__"];
thisClass->defineStatic(initName, &Function_Type);
bool hasDefaultConstructor = false;
/*
Pre-pass to declare all the methods & fields
*/
bool needsInstanceInitializer = false;
TypedRegister thisRegister = TypedRegister(0, thisClass);
if (classStmt->body) {
JSScope* thisScope = thisClass->getScope();
ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags); // constructor code generator.
ccg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod); // static initializer code generator.
StmtNode* s = classStmt->body->statements;
while (s) {
switch (s->getKind()) {
case StmtNode::Const:
case StmtNode::Var:
{
// FIXME: should preprocess all variable declarations, to prepare for method codegen.
VariableStmtNode *vs = static_cast<VariableStmtNode *>(s);
bool isStatic = hasAttribute(vs->attributes, Token::Static);
VariableBinding *v = vs->bindings;
TypedRegister thisRegister = TypedRegister(0, thisClass);
while (v) {
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = extractType(v->type);
if (isStatic) {
if (isStatic)
thisClass->defineStatic(idExpr->name, type);
if (v->initializer) {
else {
thisClass->defineSlot(idExpr->name, type);
if (v->initializer)
needsInstanceInitializer = true;
}
}
v = v->next;
}
}
break;
case StmtNode::Constructor:
case StmtNode::Function:
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(s);
bool isStatic = hasAttribute(f->attributes, Token::Static);
bool isConstructor = (s->getKind() == StmtNode::Constructor);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
if (isConstructor)
thisClass->defineConstructor(name);
else
if (isStatic)
thisClass->defineStatic(name, &Function_Type);
else {
switch (f->function.prefix) {
// XXXX these dummy place holders for the getters/setters are leaking
case FunctionName::Get:
thisClass->setGetter(name, new JSFunction(), extractType(f->function.resultType));
break;
case FunctionName::Set:
thisClass->setSetter(name, new JSFunction(), extractType(f->function.resultType));
break;
case FunctionName::normal:
thisClass->defineMethod(name, NULL);
break;
}
}
}
}
break;
default:
NOT_REACHED("unimplemented class member statement");
break;
}
s = s->next;
}
}
if (needsInstanceInitializer)
thisClass->defineStatic(mInitName, &Function_Type);
/*
Now gen code for each
*/
bool hasDefaultConstructor = false;
if (classStmt->body) {
JSScope* thisScope = thisClass->getScope();
ICodeGenerator *ccg = NULL;
if (needsInstanceInitializer) {
// constructor code generator. Slot variable
// initializers get added to this function.
ccg = new ICodeGenerator(mWorld, thisScope, thisClass, kNoFlags);
ccg->allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
}
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod); // static initializer code generator.
// static field inits, plus code to initialize
// static method slots.
StmtNode* s = classStmt->body->statements;
while (s) {
switch (s->getKind()) {
case StmtNode::Const:
case StmtNode::Var:
{
VariableStmtNode *vs = static_cast<VariableStmtNode *>(s);
bool isStatic = hasAttribute(vs->attributes, Token::Static);
VariableBinding *v = vs->bindings;
while (v) {
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
if (v->initializer) {
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = extractType(v->type);
if (isStatic) {
scg.setStatic(thisClass, idExpr->name, scg.genExpr(v->initializer));
scg.resetStatement();
}
} else {
const JSSlot& slot = thisClass->defineSlot(idExpr->name, type);
if (v->initializer) {
// generate code for the default constructor, which initializes the slots.
ccg.setSlot(thisRegister, slot.mIndex, ccg.genExpr(v->initializer));
ccg.resetStatement();
} else {
const JSSlot& slot = thisClass->getSlot(idExpr->name);
ccg->setSlot(thisRegister, slot.mIndex, ccg->genExpr(v->initializer));
ccg->resetStatement();
}
}
}
@ -1829,14 +1904,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (isConstructor) {
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
if (isStatic)
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else {
switch (f->function.prefix) {
case FunctionName::Get:
@ -1861,7 +1933,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
// add the instance initializer
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(&Void_Type)));
if (ccg) {
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg->complete(&Void_Type)));
delete ccg;
}
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
@ -1871,7 +1946,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
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);
if (thisClass->hasStatic(mInitName))
icg.call(icg.getStatic(thisClass, mInitName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(nameExpr->name);
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(&Void_Type)));
@ -2312,6 +2388,136 @@ Formatter& ICodeModule::print(Formatter& f)
return VM::operator<<(f, *its_iCode);
}
/*************************************************************************/
Formatter& operator<<(Formatter &f, string &s)
{
f << s.c_str();
return f;
}
void ICodeGenerator::readICode(const char *fileName)
{
String buffer;
int ch;
FILE *f = fopen(fileName, "r");
while ((ch = getc(f)) != EOF) buffer += static_cast<char>(ch);
fclose(f);
XMLParser xp(buffer, fileName);
XMLNode *top = xp.parseDocument();
stdOut << *top;
XMLNodeList &kids = top->children();
for (XMLNodeList::const_iterator i = kids.begin(); i != kids.end(); i++) {
XMLNode *node = *i;
if (node->name().compare(widenCString("class")) == 0) {
String className;
String superName;
JSClass* superclass = 0;
node->getValue(widenCString("name"), className);
if (node->getValue(widenCString("super"), superName)) {
const JSValue& superclassValue = mGlobal->getVariable(superName);
superclass = static_cast<JSClass*>(superclassValue.object);
}
JSClass* thisClass = new JSClass(mGlobal, className, superclass);
JSScope* thisScope = thisClass->getScope();
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod);
ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags);
ccg.allocateParameter(mWorld->identifiers["this"], thisClass);
thisClass->defineStatic(mInitName, &Function_Type);
mGlobal->defineVariable(className, &Type_Type, JSValue(thisClass));
bool hasDefaultConstructor = false;
XMLNodeList &elements = node->children();
for (XMLNodeList::const_iterator j = elements.begin(); j != elements.end(); j++) {
XMLNode *element = *j;
if (element->name().compare(widenCString("method")) == 0) {
String methodName, resultTypeName;
element->getValue(widenCString("name"), methodName);
element->getValue(widenCString("result"), resultTypeName);
JSType *resultType = findType(mWorld->identifiers[resultTypeName]);
String &body = element->body();
if (body.length()) {
std::string str(body.length(), char());
std::transform(body.begin(), body.end(), str.begin(), narrow);
ICodeParser icp;
stdOut << "Calling ICodeParser with :\n" << str << "\n";
icp.ParseSourceFromString(str);
#ifdef ROB_DONE
ICodeModule *icm = new ICodeModule(icp.instructionStream(),
NULL, /* VariableList *variables */
icp.maxRegister,
1, /* uint32 maxParameter, */
NULL, /* InstructionMap *instructionMap */
false, /* bool hasRestParameter, */
false, /* bool hasNamedRestParameter */
resultType);
thisClass->defineMethod(methodName, new JSFunction(icm));
#endif
}
}
else {
if (element->name().compare(widenCString("field")) == 0) {
String fieldName;
String fieldType;
element->getValue(widenCString("name"), fieldName);
element->getValue(widenCString("type"), fieldType);
JSType *type = findType(mWorld->identifiers[fieldType]);
if (element->hasAttribute(widenCString("static")))
thisClass->defineStatic(fieldName, type);
else {
const JSSlot& slot = thisClass->defineSlot(fieldName, type);
}
}
}
}
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg.complete(&Void_Type)));
if (!hasDefaultConstructor) {
TypedRegister thisValue = TypedRegister(0, thisClass);
ArgumentList 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);
if (thisClass->hasStatic(mInitName))
icg.call(icg.getStatic(thisClass, mInitName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(className);
scg.setStatic(thisClass, mWorld->identifiers[className], scg.newFunction(icg.complete(&Void_Type)));
}
thisClass->complete();
if (scg.getICode()->size()) {
Interpreter::Context cx(*mWorld, thisScope);
ICodeModule* clinit = scg.complete(&Void_Type);
cx.interpret(clinit, JSValues());
delete clinit;
}
}
else {
if (node->name().compare(widenCString("script")) == 0) {
}
}
}
}
} // namespace ICG

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

@ -189,6 +189,8 @@ namespace ICG {
bool mHasRestParameter; // true if this function has a ... parameter
bool mHasNamedRestParameter; // true if this function has a named ... parameter
const StringAtom &mInitName;
std::vector<bool> mPermanentRegister;
Register getTempRegister()
@ -243,7 +245,6 @@ namespace ICG {
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind;
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue);
@ -265,6 +266,7 @@ namespace ICG {
}
ICodeModule *complete(JSType *resultType);
void readICode(const char *fileName);
JSType *extractType(ExprNode *t);
@ -346,6 +348,7 @@ namespace ICG {
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
Formatter& operator<<(Formatter &f, ICodeModule &i);
Formatter& operator<<(Formatter &f, std::string &s);
/*
std::ostream &operator<<(std::ostream &s, ICodeGenerator &i);
std::ostream &operator<<(std::ostream &s, StringAtom &str);

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

@ -242,10 +242,15 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
icg.returnStmt(ret);
ICodeModule *icm = icg.complete(&Void_Type);
icm->setFileName (fileName);
icm->setFileName(fileName);
return icm;
}
void Context::loadClass(const char *fileName)
{
ICodeGenerator icg(&getWorld(), getGlobalObject());
icg.readICode(fileName); // loads it into the global object
}
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
ICodeModule* Context::getICode() { return mActivation->mICode; }

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

@ -81,6 +81,8 @@ namespace Interpreter {
ICodeModule* genCode(StmtNode *p, const String &fileName);
JSValue readEvalFile(FILE* in, const String& fileName);
void loadClass(const char *fileName);
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);

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

@ -35,6 +35,7 @@
#include "world.h"
#include "interpreter.h"
#include "icodegenerator.h"
#include "xmlparser.h"
#ifdef DEBUGGER_FOO
#include "debugger.h"
@ -211,6 +212,7 @@ class Tracer : public Context::Listener {
}
};
//#define HAVE_GEORGE_TRACE_IT
static void readEvalPrint(FILE *in, World &world)
{
@ -232,7 +234,11 @@ static void readEvalPrint(FILE *in, World &world)
Tracer *george = new Tracer();
cx.addListener(george);
#endif
#ifdef TEST_XML_LOADER
cx.loadClass("class.xml");
#endif
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
appendChars(buffer, line.data(), line.size());
try {
@ -309,6 +315,12 @@ static void testCompile()
{
JSScope glob;
Context cx(world, &glob);
#ifdef HAVE_GEORGE_TRACE_IT
Tracer *george = new Tracer();
cx.addListener(george);
#endif
glob.defineNativeFunction(world.identifiers["print"], print);
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
String testScript = widenCString(tests[i]);
@ -326,6 +338,7 @@ static void testCompile()
}
} /* namespace Shell */
} /* namespace JavaScript */
@ -341,10 +354,12 @@ int main(int , char **)
using namespace JavaScript;
using namespace Shell;
#if 1
testCompile();
#endif
readEvalPrint(stdin, world);
return 0;
// return ProcessArgs(argv + 1, argc - 1);
}

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

@ -488,7 +488,6 @@ namespace JSTypes {
ICodeModule* mICode;
protected:
JSFunction() : mICode(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -496,6 +495,8 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction() : mICode(0) {}
JSFunction(ICodeModule* iCode)
: JSObject(FunctionPrototypeObject),
mICode(iCode)

204
js/js2/xmlparser.cpp Normal file
Просмотреть файл

@ -0,0 +1,204 @@
#include <assert.h>
#include "parser.h"
#include "world.h"
#include "xmlparser.h"
namespace JavaScript {
bool XMLTag::getValue(String &name, String &value)
{
AttributeList::iterator i = mAttributeList.find(name);
if (i == mAttributeList.end())
return false;
else {
value = i->second;
return true;
}
}
void XMLParser::syntaxError(const char *msg, uint backUp)
{
mReader.unget(backUp);
mReader.error(Exception::syntaxError, widenCString(msg), mReader.getPos());
}
void XMLParser::parseName(String &id)
{
char16 ch = mReader.peek();
CharInfo chi(ch);
if (isAlpha(chi)) {
mReader.beginRecording(id);
mReader.recordChar(mReader.get());
while (true) {
ch = mReader.peek();
CharInfo chi(ch);
if (isAlphanumeric(chi))
mReader.recordChar(mReader.get());
else
break;
}
mReader.endRecording();
}
else
syntaxError("Invalid name");
}
void XMLParser::parseWhiteSpace()
{
char16 ch = mReader.peek();
CharInfo chi(ch);
while (isSpace(chi)) {
ch = mReader.get();
if (isLineBreak(ch))
mReader.beginLine();
chi = CharInfo(mReader.peek());
}
}
void XMLParser::parseAttrValue(String &val)
{
char16 ch = mReader.get();
if (ch != '\"')
syntaxError("'\"' expected");
else {
mReader.beginRecording(val);
while (true) {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated value");
if (ch == '\"')
break;
mReader.recordChar(ch);
}
mReader.endRecording();
}
}
XMLTag *XMLParser::parseTag()
{
char16 ch;
XMLTag *tag = new XMLTag();
ch = mReader.peek();
if (ch == '/') {
tag->setEndTag();
mReader.get();
}
else {
if (ch == '!') {
mReader.get();
if (mReader.peek() != '-')
syntaxError("badly formed tag");
mReader.get();
if (mReader.peek() != '-')
syntaxError("badly formed tag");
mReader.get();
while (true) {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch == '-') {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch != '-')
mReader.unget();
else {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch != '>')
syntaxError("encountered '--' in comment");
break;
}
}
if (isLineBreak(ch))
mReader.beginLine();
}
tag->setComment();
return tag;
}
}
parseName(tag->name());
parseWhiteSpace();
CharInfo chi(mReader.peek());
while (isAlpha(chi)) {
String attrValue;
String attrName;
parseName(attrName);
if (mReader.peek() == '=') {
mReader.get();
parseAttrValue(attrValue);
}
tag->addAttribute(attrName, attrValue);
parseWhiteSpace();
chi = CharInfo(mReader.peek());
}
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated tag");
if (ch == '/') {
tag->setEmpty();
ch = mReader.get();
}
if (ch != '>')
syntaxError("'>' expected");
return tag;
}
void XMLParser::parseTagBody(XMLNode *parent, XMLTag *startTag)
{
while (true) {
char16 ch = mReader.get();
while (ch != '<') {
if (mReader.getEof(ch))
syntaxError("Unterminated tag body");
parent->addToBody(ch);
ch = mReader.get();
}
XMLTag *tag = parseTag();
if (tag->isEndTag() && (tag->name().compare(startTag->name()) == 0))
break;
else {
XMLNode *child = new XMLNode(parent, tag);
if (!tag->isEmpty())
parseTagBody(child, tag);
}
}
}
XMLNode *XMLParser::parseDocument()
{
XMLNode *top = new XMLNode(NULL, new XMLTag(widenCString("TOP")));
char16 ch = mReader.get();
while (ch == '<') {
XMLTag *tag = parseTag();
XMLNode *n = new XMLNode(top, tag);
if (!tag->isEmpty()) {
parseTagBody(n, tag);
}
parseWhiteSpace();
ch = mReader.get();
if (mReader.getEof(ch))
break;
}
return top;
}
Formatter& operator<<(Formatter& f, const XMLTag& tag)
{
tag.print(f);
return f;
}
Formatter& operator<<(Formatter& f, const XMLNode& node)
{
node.print(f);
return f;
}
} /* namespace JavaScript */

131
js/js2/xmlparser.h Normal file
Просмотреть файл

@ -0,0 +1,131 @@
#include <assert.h>
#include <map>
#include "parser.h"
#include "world.h"
namespace JavaScript {
typedef enum {Tag, EmptyTag, EndTag, CommentTag, DocTypeTag, ProcessInstructionTag } TagFlag;
class XMLNode;
typedef std::vector<XMLNode *> XMLNodeList;
typedef std::multimap<String, String, std::less<String> > AttributeList;
typedef AttributeList::value_type AttributeValue;
class XMLTag {
public:
XMLTag() : mFlag(Tag) { }
XMLTag(String name) : mName(name), mFlag(Tag) { }
void addAttribute(String name, String value) { mAttributeList.insert(AttributeValue(name, value) ); }
bool getValue(String &name, String &value);
bool hasAttribute(String &name) { return (mAttributeList.find(name) != mAttributeList.end()); }
String &name() { return mName; }
void setEmpty() { mFlag = EmptyTag; }
void setComment() { mFlag = EmptyTag; }
void setEndTag() { mFlag = EndTag; }
bool isEmpty() const { return mFlag == EmptyTag; }
bool isEndTag() const { return mFlag == EndTag; }
bool isComment() const { return mFlag == CommentTag; }
String mName;
TagFlag mFlag;
AttributeList mAttributeList;
void print(Formatter& f) const
{
if (isComment())
f << "XML Comment tag\n";
else
f << "XMLTag '" << mName << "'\n";
for (AttributeList::const_iterator i = mAttributeList.begin(); i != mAttributeList.end(); i++) {
f << "\t'" << i->first << "' = '" << i->second << "'\n";
}
}
};
Formatter& operator<<(Formatter& f, const XMLTag& tag);
Formatter& operator<<(Formatter& f, const XMLNode& node);
class XMLNode
{
public:
XMLNode(XMLNode *parent, XMLTag *tag) : mParent(parent), mTag(tag) { if (parent) parent->addChild(this); }
String &name() { return mTag->name(); }
XMLTag *tag() { return mTag; }
String &body() { return mBody; }
void addToBody(String contents) { mBody += contents; }
void addToBody(char16 ch) { mBody += ch; }
void addChild(XMLNode *child) { mChildren.push_back(child); }
XMLNodeList &children() { return mChildren; }
bool getValue(String &name, String &value)
{ return mTag->getValue(name, value); }
bool hasAttribute(String &name) { return mTag->hasAttribute(name); }
void print(Formatter& f) const
{
f << *mTag;
if (mParent)
f << "parent = '" << mParent->name() << "'";
else
f << "parent = NULL";
XMLNodeList::const_iterator i = mChildren.begin();
XMLNodeList::const_iterator end = mChildren.end();
if (i != end) {
f << "\nChildren :\n";
while (i != end) {
f << **i;
f << "\n";
i++;
}
}
f << "\n";
}
XMLNodeList mChildren;
XMLNode *mParent;
XMLTag *mTag;
String mBody;
};
class XMLParser {
public:
void syntaxError(const char *message, uint backUp = 1);
char16 doEscape();
XMLParser(const String &source, const char *fileName) : mReader(source, widenCString(fileName)) { }
void parseName(String &id);
void parseWhiteSpace();
void parseAttrValue(String &val);
XMLTag *parseTag();
void parseTagBody(XMLNode *parent, XMLTag *startTag);
XMLNode *parseDocument();
Reader mReader;
};
} /* namespace JavaScript */

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

@ -38,6 +38,8 @@
#include "jsclasses.h"
#include "icodegenerator.h"
#include "interpreter.h"
#include "xmlparser.h"
#include "icodeasm.h"
#include <stdexcept>
#include <stdio.h>
@ -49,6 +51,7 @@ using namespace VM;
using namespace JSTypes;
using namespace JSClasses;
using namespace Interpreter;
using namespace ICodeASM;
inline char narrow(char16 ch) { return char(ch); }
@ -82,7 +85,8 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I
mFlags(flags),
pLabels(NULL),
mHasRestParameter(false),
mHasNamedRestParameter(false)
mHasNamedRestParameter(false),
mInitName(world->identifiers["__init__"])
{
iCode = new InstructionStream();
iCodeOwner = true;
@ -1724,8 +1728,9 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor
icg.call(icg.getStatic(superclass, superclass->getName()), thisValue, &args);
}
}
const StringAtom &initName = mWorld->identifiers["__init__"]; // XXXXXXX
icg.call(icg.getStatic(mClass, initName), thisValue, &args); // ok, so it's mis-named
if (mClass->hasStatic(mInitName))
icg.call(icg.getStatic(mClass, mInitName), thisValue, &args); // ok, so it's mis-named
}
if (f->function.body)
icg.genStmt(f->function.body);
@ -1765,48 +1770,118 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
// to handle recursive types, such as linked list nodes.
mGlobal->defineVariable(nameExpr->name, &Type_Type, JSValue(thisClass));
// Have to have this declared ahead of time so that it's slot can
// be discoverd when compiling constructors in the loop below. Could
// do a pre-processing loop to discover whether it is in fact empty
// and then pass that info through to the genFunction() call for each
// constructor.
const StringAtom &initName = mWorld->identifiers["__init__"];
thisClass->defineStatic(initName, &Function_Type);
bool hasDefaultConstructor = false;
/*
Pre-pass to declare all the methods & fields
*/
bool needsInstanceInitializer = false;
TypedRegister thisRegister = TypedRegister(0, thisClass);
if (classStmt->body) {
JSScope* thisScope = thisClass->getScope();
ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags); // constructor code generator.
ccg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod); // static initializer code generator.
StmtNode* s = classStmt->body->statements;
while (s) {
switch (s->getKind()) {
case StmtNode::Const:
case StmtNode::Var:
{
// FIXME: should preprocess all variable declarations, to prepare for method codegen.
VariableStmtNode *vs = static_cast<VariableStmtNode *>(s);
bool isStatic = hasAttribute(vs->attributes, Token::Static);
VariableBinding *v = vs->bindings;
TypedRegister thisRegister = TypedRegister(0, thisClass);
while (v) {
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = extractType(v->type);
if (isStatic) {
if (isStatic)
thisClass->defineStatic(idExpr->name, type);
if (v->initializer) {
else {
thisClass->defineSlot(idExpr->name, type);
if (v->initializer)
needsInstanceInitializer = true;
}
}
v = v->next;
}
}
break;
case StmtNode::Constructor:
case StmtNode::Function:
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(s);
bool isStatic = hasAttribute(f->attributes, Token::Static);
bool isConstructor = (s->getKind() == StmtNode::Constructor);
if (f->function.name->getKind() == ExprNode::identifier) {
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
if (isConstructor)
thisClass->defineConstructor(name);
else
if (isStatic)
thisClass->defineStatic(name, &Function_Type);
else {
switch (f->function.prefix) {
// XXXX these dummy place holders for the getters/setters are leaking
case FunctionName::Get:
thisClass->setGetter(name, new JSFunction(), extractType(f->function.resultType));
break;
case FunctionName::Set:
thisClass->setSetter(name, new JSFunction(), extractType(f->function.resultType));
break;
case FunctionName::normal:
thisClass->defineMethod(name, NULL);
break;
}
}
}
}
break;
default:
NOT_REACHED("unimplemented class member statement");
break;
}
s = s->next;
}
}
if (needsInstanceInitializer)
thisClass->defineStatic(mInitName, &Function_Type);
/*
Now gen code for each
*/
bool hasDefaultConstructor = false;
if (classStmt->body) {
JSScope* thisScope = thisClass->getScope();
ICodeGenerator *ccg = NULL;
if (needsInstanceInitializer) {
// constructor code generator. Slot variable
// initializers get added to this function.
ccg = new ICodeGenerator(mWorld, thisScope, thisClass, kNoFlags);
ccg->allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0
}
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod); // static initializer code generator.
// static field inits, plus code to initialize
// static method slots.
StmtNode* s = classStmt->body->statements;
while (s) {
switch (s->getKind()) {
case StmtNode::Const:
case StmtNode::Var:
{
VariableStmtNode *vs = static_cast<VariableStmtNode *>(s);
bool isStatic = hasAttribute(vs->attributes, Token::Static);
VariableBinding *v = vs->bindings;
while (v) {
if (v->name) {
ASSERT(v->name->getKind() == ExprNode::identifier);
if (v->initializer) {
IdentifierExprNode* idExpr = static_cast<IdentifierExprNode*>(v->name);
JSType* type = extractType(v->type);
if (isStatic) {
scg.setStatic(thisClass, idExpr->name, scg.genExpr(v->initializer));
scg.resetStatement();
}
} else {
const JSSlot& slot = thisClass->defineSlot(idExpr->name, type);
if (v->initializer) {
// generate code for the default constructor, which initializes the slots.
ccg.setSlot(thisRegister, slot.mIndex, ccg.genExpr(v->initializer));
ccg.resetStatement();
} else {
const JSSlot& slot = thisClass->getSlot(idExpr->name);
ccg->setSlot(thisRegister, slot.mIndex, ccg->genExpr(v->initializer));
ccg->resetStatement();
}
}
}
@ -1829,14 +1904,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
if (isConstructor) {
if (name == nameExpr->name)
hasDefaultConstructor = true;
thisClass->defineConstructor(name);
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else
if (isStatic) {
thisClass->defineStatic(name, &Function_Type);
if (isStatic)
scg.setStatic(thisClass, name, scg.newFunction(icm));
}
else {
switch (f->function.prefix) {
case FunctionName::Get:
@ -1861,7 +1933,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
// add the instance initializer
scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(&Void_Type)));
if (ccg) {
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg->complete(&Void_Type)));
delete ccg;
}
// invent a default constructor if necessary, it just calls the
// initializer and the superclass default constructor
if (!hasDefaultConstructor) {
@ -1871,7 +1946,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
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);
if (thisClass->hasStatic(mInitName))
icg.call(icg.getStatic(thisClass, mInitName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(nameExpr->name);
scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(&Void_Type)));
@ -2312,6 +2388,136 @@ Formatter& ICodeModule::print(Formatter& f)
return VM::operator<<(f, *its_iCode);
}
/*************************************************************************/
Formatter& operator<<(Formatter &f, string &s)
{
f << s.c_str();
return f;
}
void ICodeGenerator::readICode(const char *fileName)
{
String buffer;
int ch;
FILE *f = fopen(fileName, "r");
while ((ch = getc(f)) != EOF) buffer += static_cast<char>(ch);
fclose(f);
XMLParser xp(buffer, fileName);
XMLNode *top = xp.parseDocument();
stdOut << *top;
XMLNodeList &kids = top->children();
for (XMLNodeList::const_iterator i = kids.begin(); i != kids.end(); i++) {
XMLNode *node = *i;
if (node->name().compare(widenCString("class")) == 0) {
String className;
String superName;
JSClass* superclass = 0;
node->getValue(widenCString("name"), className);
if (node->getValue(widenCString("super"), superName)) {
const JSValue& superclassValue = mGlobal->getVariable(superName);
superclass = static_cast<JSClass*>(superclassValue.object);
}
JSClass* thisClass = new JSClass(mGlobal, className, superclass);
JSScope* thisScope = thisClass->getScope();
ICodeGenerator scg(mWorld, thisScope, thisClass, kIsStaticMethod);
ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags);
ccg.allocateParameter(mWorld->identifiers["this"], thisClass);
thisClass->defineStatic(mInitName, &Function_Type);
mGlobal->defineVariable(className, &Type_Type, JSValue(thisClass));
bool hasDefaultConstructor = false;
XMLNodeList &elements = node->children();
for (XMLNodeList::const_iterator j = elements.begin(); j != elements.end(); j++) {
XMLNode *element = *j;
if (element->name().compare(widenCString("method")) == 0) {
String methodName, resultTypeName;
element->getValue(widenCString("name"), methodName);
element->getValue(widenCString("result"), resultTypeName);
JSType *resultType = findType(mWorld->identifiers[resultTypeName]);
String &body = element->body();
if (body.length()) {
std::string str(body.length(), char());
std::transform(body.begin(), body.end(), str.begin(), narrow);
ICodeParser icp;
stdOut << "Calling ICodeParser with :\n" << str << "\n";
icp.ParseSourceFromString(str);
#ifdef ROB_DONE
ICodeModule *icm = new ICodeModule(icp.instructionStream(),
NULL, /* VariableList *variables */
icp.maxRegister,
1, /* uint32 maxParameter, */
NULL, /* InstructionMap *instructionMap */
false, /* bool hasRestParameter, */
false, /* bool hasNamedRestParameter */
resultType);
thisClass->defineMethod(methodName, new JSFunction(icm));
#endif
}
}
else {
if (element->name().compare(widenCString("field")) == 0) {
String fieldName;
String fieldType;
element->getValue(widenCString("name"), fieldName);
element->getValue(widenCString("type"), fieldType);
JSType *type = findType(mWorld->identifiers[fieldType]);
if (element->hasAttribute(widenCString("static")))
thisClass->defineStatic(fieldName, type);
else {
const JSSlot& slot = thisClass->defineSlot(fieldName, type);
}
}
}
}
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg.complete(&Void_Type)));
if (!hasDefaultConstructor) {
TypedRegister thisValue = TypedRegister(0, thisClass);
ArgumentList 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);
if (thisClass->hasStatic(mInitName))
icg.call(icg.getStatic(thisClass, mInitName), thisValue, &args);
icg.returnStmt(thisValue);
thisClass->defineConstructor(className);
scg.setStatic(thisClass, mWorld->identifiers[className], scg.newFunction(icg.complete(&Void_Type)));
}
thisClass->complete();
if (scg.getICode()->size()) {
Interpreter::Context cx(*mWorld, thisScope);
ICodeModule* clinit = scg.complete(&Void_Type);
cx.interpret(clinit, JSValues());
delete clinit;
}
}
else {
if (node->name().compare(widenCString("script")) == 0) {
}
}
}
}
} // namespace ICG

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

@ -189,6 +189,8 @@ namespace ICG {
bool mHasRestParameter; // true if this function has a ... parameter
bool mHasNamedRestParameter; // true if this function has a named ... parameter
const StringAtom &mInitName;
std::vector<bool> mPermanentRegister;
Register getTempRegister()
@ -243,7 +245,6 @@ namespace ICG {
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind;
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue);
@ -265,6 +266,7 @@ namespace ICG {
}
ICodeModule *complete(JSType *resultType);
void readICode(const char *fileName);
JSType *extractType(ExprNode *t);
@ -346,6 +348,7 @@ namespace ICG {
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
Formatter& operator<<(Formatter &f, ICodeModule &i);
Formatter& operator<<(Formatter &f, std::string &s);
/*
std::ostream &operator<<(std::ostream &s, ICodeGenerator &i);
std::ostream &operator<<(std::ostream &s, StringAtom &str);

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

@ -242,10 +242,15 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
icg.returnStmt(ret);
ICodeModule *icm = icg.complete(&Void_Type);
icm->setFileName (fileName);
icm->setFileName(fileName);
return icm;
}
void Context::loadClass(const char *fileName)
{
ICodeGenerator icg(&getWorld(), getGlobalObject());
icg.readICode(fileName); // loads it into the global object
}
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
ICodeModule* Context::getICode() { return mActivation->mICode; }

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

@ -81,6 +81,8 @@ namespace Interpreter {
ICodeModule* genCode(StmtNode *p, const String &fileName);
JSValue readEvalFile(FILE* in, const String& fileName);
void loadClass(const char *fileName);
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);

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

@ -488,7 +488,6 @@ namespace JSTypes {
ICodeModule* mICode;
protected:
JSFunction() : mICode(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
@ -496,6 +495,8 @@ namespace JSTypes {
public:
static void initFunctionObject(JSScope *g);
JSFunction() : mICode(0) {}
JSFunction(ICodeModule* iCode)
: JSObject(FunctionPrototypeObject),
mICode(iCode)

204
js2/src/xmlparser.cpp Normal file
Просмотреть файл

@ -0,0 +1,204 @@
#include <assert.h>
#include "parser.h"
#include "world.h"
#include "xmlparser.h"
namespace JavaScript {
bool XMLTag::getValue(String &name, String &value)
{
AttributeList::iterator i = mAttributeList.find(name);
if (i == mAttributeList.end())
return false;
else {
value = i->second;
return true;
}
}
void XMLParser::syntaxError(const char *msg, uint backUp)
{
mReader.unget(backUp);
mReader.error(Exception::syntaxError, widenCString(msg), mReader.getPos());
}
void XMLParser::parseName(String &id)
{
char16 ch = mReader.peek();
CharInfo chi(ch);
if (isAlpha(chi)) {
mReader.beginRecording(id);
mReader.recordChar(mReader.get());
while (true) {
ch = mReader.peek();
CharInfo chi(ch);
if (isAlphanumeric(chi))
mReader.recordChar(mReader.get());
else
break;
}
mReader.endRecording();
}
else
syntaxError("Invalid name");
}
void XMLParser::parseWhiteSpace()
{
char16 ch = mReader.peek();
CharInfo chi(ch);
while (isSpace(chi)) {
ch = mReader.get();
if (isLineBreak(ch))
mReader.beginLine();
chi = CharInfo(mReader.peek());
}
}
void XMLParser::parseAttrValue(String &val)
{
char16 ch = mReader.get();
if (ch != '\"')
syntaxError("'\"' expected");
else {
mReader.beginRecording(val);
while (true) {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated value");
if (ch == '\"')
break;
mReader.recordChar(ch);
}
mReader.endRecording();
}
}
XMLTag *XMLParser::parseTag()
{
char16 ch;
XMLTag *tag = new XMLTag();
ch = mReader.peek();
if (ch == '/') {
tag->setEndTag();
mReader.get();
}
else {
if (ch == '!') {
mReader.get();
if (mReader.peek() != '-')
syntaxError("badly formed tag");
mReader.get();
if (mReader.peek() != '-')
syntaxError("badly formed tag");
mReader.get();
while (true) {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch == '-') {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch != '-')
mReader.unget();
else {
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated comment tag");
if (ch != '>')
syntaxError("encountered '--' in comment");
break;
}
}
if (isLineBreak(ch))
mReader.beginLine();
}
tag->setComment();
return tag;
}
}
parseName(tag->name());
parseWhiteSpace();
CharInfo chi(mReader.peek());
while (isAlpha(chi)) {
String attrValue;
String attrName;
parseName(attrName);
if (mReader.peek() == '=') {
mReader.get();
parseAttrValue(attrValue);
}
tag->addAttribute(attrName, attrValue);
parseWhiteSpace();
chi = CharInfo(mReader.peek());
}
ch = mReader.get();
if (mReader.getEof(ch))
syntaxError("Unterminated tag");
if (ch == '/') {
tag->setEmpty();
ch = mReader.get();
}
if (ch != '>')
syntaxError("'>' expected");
return tag;
}
void XMLParser::parseTagBody(XMLNode *parent, XMLTag *startTag)
{
while (true) {
char16 ch = mReader.get();
while (ch != '<') {
if (mReader.getEof(ch))
syntaxError("Unterminated tag body");
parent->addToBody(ch);
ch = mReader.get();
}
XMLTag *tag = parseTag();
if (tag->isEndTag() && (tag->name().compare(startTag->name()) == 0))
break;
else {
XMLNode *child = new XMLNode(parent, tag);
if (!tag->isEmpty())
parseTagBody(child, tag);
}
}
}
XMLNode *XMLParser::parseDocument()
{
XMLNode *top = new XMLNode(NULL, new XMLTag(widenCString("TOP")));
char16 ch = mReader.get();
while (ch == '<') {
XMLTag *tag = parseTag();
XMLNode *n = new XMLNode(top, tag);
if (!tag->isEmpty()) {
parseTagBody(n, tag);
}
parseWhiteSpace();
ch = mReader.get();
if (mReader.getEof(ch))
break;
}
return top;
}
Formatter& operator<<(Formatter& f, const XMLTag& tag)
{
tag.print(f);
return f;
}
Formatter& operator<<(Formatter& f, const XMLNode& node)
{
node.print(f);
return f;
}
} /* namespace JavaScript */

131
js2/src/xmlparser.h Normal file
Просмотреть файл

@ -0,0 +1,131 @@
#include <assert.h>
#include <map>
#include "parser.h"
#include "world.h"
namespace JavaScript {
typedef enum {Tag, EmptyTag, EndTag, CommentTag, DocTypeTag, ProcessInstructionTag } TagFlag;
class XMLNode;
typedef std::vector<XMLNode *> XMLNodeList;
typedef std::multimap<String, String, std::less<String> > AttributeList;
typedef AttributeList::value_type AttributeValue;
class XMLTag {
public:
XMLTag() : mFlag(Tag) { }
XMLTag(String name) : mName(name), mFlag(Tag) { }
void addAttribute(String name, String value) { mAttributeList.insert(AttributeValue(name, value) ); }
bool getValue(String &name, String &value);
bool hasAttribute(String &name) { return (mAttributeList.find(name) != mAttributeList.end()); }
String &name() { return mName; }
void setEmpty() { mFlag = EmptyTag; }
void setComment() { mFlag = EmptyTag; }
void setEndTag() { mFlag = EndTag; }
bool isEmpty() const { return mFlag == EmptyTag; }
bool isEndTag() const { return mFlag == EndTag; }
bool isComment() const { return mFlag == CommentTag; }
String mName;
TagFlag mFlag;
AttributeList mAttributeList;
void print(Formatter& f) const
{
if (isComment())
f << "XML Comment tag\n";
else
f << "XMLTag '" << mName << "'\n";
for (AttributeList::const_iterator i = mAttributeList.begin(); i != mAttributeList.end(); i++) {
f << "\t'" << i->first << "' = '" << i->second << "'\n";
}
}
};
Formatter& operator<<(Formatter& f, const XMLTag& tag);
Formatter& operator<<(Formatter& f, const XMLNode& node);
class XMLNode
{
public:
XMLNode(XMLNode *parent, XMLTag *tag) : mParent(parent), mTag(tag) { if (parent) parent->addChild(this); }
String &name() { return mTag->name(); }
XMLTag *tag() { return mTag; }
String &body() { return mBody; }
void addToBody(String contents) { mBody += contents; }
void addToBody(char16 ch) { mBody += ch; }
void addChild(XMLNode *child) { mChildren.push_back(child); }
XMLNodeList &children() { return mChildren; }
bool getValue(String &name, String &value)
{ return mTag->getValue(name, value); }
bool hasAttribute(String &name) { return mTag->hasAttribute(name); }
void print(Formatter& f) const
{
f << *mTag;
if (mParent)
f << "parent = '" << mParent->name() << "'";
else
f << "parent = NULL";
XMLNodeList::const_iterator i = mChildren.begin();
XMLNodeList::const_iterator end = mChildren.end();
if (i != end) {
f << "\nChildren :\n";
while (i != end) {
f << **i;
f << "\n";
i++;
}
}
f << "\n";
}
XMLNodeList mChildren;
XMLNode *mParent;
XMLTag *mTag;
String mBody;
};
class XMLParser {
public:
void syntaxError(const char *message, uint backUp = 1);
char16 doEscape();
XMLParser(const String &source, const char *fileName) : mReader(source, widenCString(fileName)) { }
void parseName(String &id);
void parseWhiteSpace();
void parseAttrValue(String &val);
XMLTag *parseTag();
void parseTagBody(XMLNode *parent, XMLTag *startTag);
XMLNode *parseDocument();
Reader mReader;
};
} /* namespace JavaScript */

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

@ -35,6 +35,7 @@
#include "world.h"
#include "interpreter.h"
#include "icodegenerator.h"
#include "xmlparser.h"
#ifdef DEBUGGER_FOO
#include "debugger.h"
@ -211,6 +212,7 @@ class Tracer : public Context::Listener {
}
};
//#define HAVE_GEORGE_TRACE_IT
static void readEvalPrint(FILE *in, World &world)
{
@ -232,7 +234,11 @@ static void readEvalPrint(FILE *in, World &world)
Tracer *george = new Tracer();
cx.addListener(george);
#endif
#ifdef TEST_XML_LOADER
cx.loadClass("class.xml");
#endif
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
appendChars(buffer, line.data(), line.size());
try {
@ -309,6 +315,12 @@ static void testCompile()
{
JSScope glob;
Context cx(world, &glob);
#ifdef HAVE_GEORGE_TRACE_IT
Tracer *george = new Tracer();
cx.addListener(george);
#endif
glob.defineNativeFunction(world.identifiers["print"], print);
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
String testScript = widenCString(tests[i]);
@ -326,6 +338,7 @@ static void testCompile()
}
} /* namespace Shell */
} /* namespace JavaScript */
@ -341,10 +354,12 @@ int main(int , char **)
using namespace JavaScript;
using namespace Shell;
#if 1
testCompile();
#endif
readEvalPrint(stdin, world);
return 0;
// return ProcessArgs(argv + 1, argc - 1);
}