incremental
git-svn-id: svn://10.0.0.236/trunk@126277 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
a99f9fc6ea
commit
4736214ba3
@ -143,7 +143,7 @@ static int readEvalPrint(FILE *in)
|
||||
MetaData::Context cxt;
|
||||
|
||||
metadata->ValidateStmtList(&cxt, &env, parsedStatements);
|
||||
metadata->EvalStmtList(&env, MetaData::JS2Metadata::RunPhase, parsedStatements);
|
||||
metadata->EvalStmtList(&env, MetaData::RunPhase, parsedStatements);
|
||||
|
||||
}
|
||||
clear(buffer);
|
||||
|
||||
@ -76,60 +76,145 @@ namespace MetaData {
|
||||
JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,
|
||||
JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub };
|
||||
|
||||
JSClass gMonkeyLexicalReferenceClass = { "LexicalReference", 0, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,
|
||||
JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub };
|
||||
JSClass gMonkeyMultinameClass =
|
||||
{ "Multiname", 0, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,
|
||||
JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub };
|
||||
|
||||
static JSBool
|
||||
LexicalReference_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
ASSERT(argc == 3);
|
||||
ASSERT(JSVAL_IS_STRING(argv[0]));
|
||||
ASSERT(JSVAL_IS_BOOLEAN(argv[1]));
|
||||
ASSERT(JSVAL_IS_NULL(argv[2]) || JSVAL_IS_OBJECT(argv[2]));
|
||||
|
||||
JSString *str = JSVAL_TO_STRING(argv[0]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_SetProperty(cx, obj, "name", argv[0]))
|
||||
return JS_FALSE;
|
||||
// forward ref.
|
||||
static void LexicalReference_finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
JSClass gMonkeyLexicalReferenceClass =
|
||||
{ "LexicalReference", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,
|
||||
JS_ResolveStub, JS_ConvertStub, LexicalReference_finalize };
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
readReference(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
// for this reference, use the
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
writeReference(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSFunctionSpec jsfLexicalReference [] =
|
||||
{
|
||||
{ "readReference", readReference, 0, 0, 0 },
|
||||
{ "writeReference", writeReference, 0, 0, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
// member functions at global scope
|
||||
JSFunctionSpec jsfGlobal [] =
|
||||
{
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
// The Monkey error handler, simply throws back to JS2MetaData
|
||||
void MonkeyError(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
{
|
||||
throw message;
|
||||
}
|
||||
|
||||
void JS2Metadata::initializeMonkey( )
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
LexicalReference
|
||||
******************************************************************************/
|
||||
|
||||
// finish constructing a LexicalReference
|
||||
static JSBool
|
||||
LexicalReference_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
ExecutionState *eState = static_cast<ExecutionState *>(JS_GetContextPrivate(cx));
|
||||
|
||||
ASSERT(argc == 2);
|
||||
ASSERT(JSVAL_IS_BOOLEAN(argv[0])); // the 'strict' flag (XXX what's that for?)
|
||||
ASSERT(JSVAL_IS_OBJECT(argv[1])); // the multiname object
|
||||
|
||||
JSObject *multiNameObj = JSVAL_TO_OBJECT(argv[1]);
|
||||
ASSERT(OBJ_GET_CLASS(cx, multiNameObj) == &gMonkeyMultinameClass);
|
||||
Multiname *mName = static_cast<Multiname *>(JS_GetPrivate(cx, multiNameObj));
|
||||
|
||||
if (!JS_SetPrivate(cx, obj, new LexicalReference(mName, eState->env, (JSVAL_TO_BOOLEAN(argv[0])) == JS_TRUE) ))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// finalize a LexicalReference - called by Monkey gc
|
||||
static void
|
||||
LexicalReference_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
ASSERT(OBJ_GET_CLASS(cx, obj) == &gMonkeyLexicalReferenceClass);
|
||||
LexicalReference *lRef = static_cast<LexicalReference *>(JS_GetPrivate(cx, obj));
|
||||
if (lRef) delete lRef;
|
||||
}
|
||||
|
||||
// Given a LexicalReference, read it's contents
|
||||
static JSBool
|
||||
readLexicalReference(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
ASSERT(OBJ_GET_CLASS(cx, obj) == &gMonkeyLexicalReferenceClass);
|
||||
ExecutionState *eState = static_cast<ExecutionState *>(JS_GetContextPrivate(cx));
|
||||
LexicalReference *lRef = static_cast<LexicalReference *>(JS_GetPrivate(cx, obj));
|
||||
|
||||
eState->env->lexicalRead(eState, lRef->variableMultiname, RunPhase);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// Write a value into a LexicalReference
|
||||
static JSBool
|
||||
writeLexicalReference(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
ASSERT(OBJ_GET_CLASS(cx, obj) == &gMonkeyLexicalReferenceClass);
|
||||
ExecutionState *eState = static_cast<ExecutionState *>(JS_GetContextPrivate(cx));
|
||||
LexicalReference *lRef = static_cast<LexicalReference *>(JS_GetPrivate(cx, obj));
|
||||
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// member functions in a LexicalReference
|
||||
JSFunctionSpec jsfLexicalReference [] =
|
||||
{
|
||||
{ "readReference", readLexicalReference, 0, 0, 0 },
|
||||
{ "writeReference", writeLexicalReference, 0, 0, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Multiname
|
||||
******************************************************************************/
|
||||
|
||||
// finish constructing a Multiname
|
||||
static JSBool
|
||||
Multiname_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
ASSERT(argc >= 1); // could be just the base name
|
||||
ASSERT(OBJ_GET_CLASS(cx, obj) == &gMonkeyMultinameClass);
|
||||
|
||||
ASSERT(JSVAL_IS_STRING(argv[0]));
|
||||
|
||||
// XXX use reserved slots instead
|
||||
if (!JS_SetProperty(cx, obj, "name", &argv[0]))
|
||||
return JS_FALSE;
|
||||
|
||||
jsval qualifierVal = JSVAL_NULL;
|
||||
if (argc > 1) {
|
||||
JSObject *qualArray = JS_NewArrayObject(cx, argc - 1, &argv[1]);
|
||||
if (!qualArray)
|
||||
return JS_FALSE;
|
||||
qualifierVal = OBJECT_TO_JSVAL(qualArray);
|
||||
}
|
||||
if (!JS_SetProperty(cx, obj, "qualifiers", &qualifierVal))
|
||||
return JS_FALSE;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
// member functions in a Multiname
|
||||
JSFunctionSpec jsfMultiname [] =
|
||||
{
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Initialize the SpiderMonkey engine
|
||||
void JS2Metadata::initializeMonkey()
|
||||
{
|
||||
gMonkeyRuntime = JS_NewRuntime( 1000000L );
|
||||
if (!gMonkeyRuntime)
|
||||
@ -139,6 +224,7 @@ namespace MetaData {
|
||||
if (!gMonkeyContext)
|
||||
throw "Monkey start failure";
|
||||
|
||||
|
||||
gMonkeyGlobalObject = JS_NewObject(gMonkeyContext, &gMonkeyGlobalClass, NULL, NULL);
|
||||
if (!gMonkeyGlobalObject)
|
||||
throw "Monkey start failure";
|
||||
@ -149,17 +235,25 @@ namespace MetaData {
|
||||
|
||||
JS_InitClass(gMonkeyContext, gMonkeyGlobalObject, NULL,
|
||||
&gMonkeyLexicalReferenceClass, LexicalReference_constructor, 0,
|
||||
NULL, jsfLexicalReference,
|
||||
NULL, NULL);
|
||||
NULL, jsfLexicalReference, NULL, NULL);
|
||||
|
||||
JS_InitClass(gMonkeyContext, gMonkeyGlobalObject, NULL,
|
||||
&gMonkeyMultinameClass, Multiname_constructor, 0,
|
||||
NULL, jsfMultiname, NULL, NULL);
|
||||
|
||||
JS_DefineFunctions(gMonkeyContext, gMonkeyGlobalObject, jsfGlobal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
jsval JS2Metadata::execute(String *str)
|
||||
// Execute a JS string against the given environment
|
||||
// Errors are thrown back to C++ by the error handler
|
||||
jsval JS2Metadata::execute(String *str, Environment *env, JS2Metadata *meta, size_t pos)
|
||||
{
|
||||
jsval retval;
|
||||
|
||||
ExecutionState eState(gMonkeyContext, env, meta, pos);
|
||||
JS_SetContextPrivate(gMonkeyContext, &eState);
|
||||
|
||||
JS_EvaluateUCScript(gMonkeyContext, gMonkeyGlobalObject, str->c_str(), str->length(), "file", 1, &retval);
|
||||
|
||||
return retval;
|
||||
|
||||
@ -440,7 +440,7 @@ namespace MetaData {
|
||||
String s;
|
||||
EvalExprNode(env, phase, p, s);
|
||||
try {
|
||||
return execute(&s);
|
||||
return execute(&s, env, this, p->pos);
|
||||
}
|
||||
catch (const char *err) {
|
||||
reportError(Exception::internalError, err, p->pos);
|
||||
@ -477,7 +477,7 @@ namespace MetaData {
|
||||
s += r + ")";
|
||||
}
|
||||
else
|
||||
ASSERT(false); // shouldn't this have been checked by validate?
|
||||
ASSERT(false); // not an lvalue, shouldn't this have been checked by validate?
|
||||
}
|
||||
break;
|
||||
case ExprNode::add:
|
||||
@ -497,6 +497,8 @@ namespace MetaData {
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
// rather than inserting "(r = , a = readRef(), r.writeRef(a + 1), a)" with
|
||||
// all the attendant performance overhead and temp. handling issues.
|
||||
if (!EvalExprNode(env, phase, u->op, s))
|
||||
ASSERT(false); // not an lvalue
|
||||
s += ".postIncrement()";
|
||||
returningRef = true;
|
||||
}
|
||||
@ -510,24 +512,13 @@ namespace MetaData {
|
||||
case ExprNode::identifier:
|
||||
{
|
||||
IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
|
||||
s += "new LexicalReference(\"" + i->name + "\", ";
|
||||
s += (i->cxt->strict) ? "true, " : "false, ";
|
||||
NamespaceListIterator nli = i->cxt->openNamespaces.begin(), end = i->cxt->openNamespaces.end();
|
||||
if (nli != end) {
|
||||
s += "new Multiname(";
|
||||
while (true) {
|
||||
s += (*nli)->name;
|
||||
nli++;
|
||||
if (nli != end)
|
||||
s += ", ";
|
||||
else
|
||||
break;
|
||||
}
|
||||
s += ")";
|
||||
s += "new LexicalReference(" + (i->cxt->strict) ? "true, " : "false, ";
|
||||
s += "new Multiname(\"" + i->name + "\"";
|
||||
for (NamespaceListIterator nli = i->cxt->openNamespaces.begin(), end = i->cxt->openNamespaces.end();
|
||||
(nli != end); nli++) {
|
||||
s += ", " + (*nli)->name;
|
||||
}
|
||||
else
|
||||
s += "null";
|
||||
s += ")";
|
||||
s += "))";
|
||||
returningRef = true;
|
||||
}
|
||||
break;
|
||||
@ -577,6 +568,48 @@ namespace MetaData {
|
||||
return pf;
|
||||
}
|
||||
|
||||
// findThis returns the value of this. If allowPrototypeThis is true, allow this to be defined
|
||||
// by either an instance member of a class or a prototype function. If allowPrototypeThis is
|
||||
// false, allow this to be defined only by an instance member of a class.
|
||||
jsval Environment::findThis(bool allowPrototypeThis)
|
||||
{
|
||||
Frame *pf = firstFrame;
|
||||
while (pf) {
|
||||
if ((pf->kind == Frame::Function)
|
||||
&& !JSVAL_IS_NULL(checked_cast<FunctionFrame *>(pf)->thisObject))
|
||||
if (allowPrototypeThis || !checked_cast<FunctionFrame *>(pf)->prototype)
|
||||
return checked_cast<FunctionFrame *>(pf)->thisObject;
|
||||
pf = pf->nextFrame;
|
||||
}
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
||||
// Slightly varies from spec. - the multiname is actually the list of
|
||||
// qualifiers to apply to the name
|
||||
jsval Environment::lexicalRead(ExecutionState *eState, Multiname *multiname, Phase phase)
|
||||
{
|
||||
LookupKind lookup(true, findThis(false));
|
||||
Frame *pf = firstFrame;
|
||||
while (pf) {
|
||||
jsval rval;
|
||||
if (readProperty(eState, pf, multiname, &lookup, phase, &rval))
|
||||
return rval;
|
||||
|
||||
pf = pf->nextFrame;
|
||||
}
|
||||
eState->meta->reportError(Exception::referenceError, "{0} is undefined", eState->pos, multiname->name);
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Environment::readProperty(ExecutionState *eState, jsval container, Multiname *multinameVal, LookupKind *lookupKind, Phase phase, jsval *rval)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* Context
|
||||
@ -651,6 +684,34 @@ namespace MetaData {
|
||||
initializeMonkey();
|
||||
}
|
||||
|
||||
// objectType(o) returns an OBJECT o's most specific type.
|
||||
JS2Class *JS2Metadata::objectType(jsval obj)
|
||||
{
|
||||
if (JSVAL_IS_VOID(obj))
|
||||
return undefinedClass;
|
||||
if (JSVAL_IS_NULL(obj))
|
||||
return nullClass;
|
||||
if (JSVAL_IS_BOOLEAN(obj))
|
||||
return booleanClass;
|
||||
if (JSVAL_IS_NUMBER(obj))
|
||||
return numberClass;
|
||||
if (JSVAL_IS_STRING(obj)) {
|
||||
if (JS_GetStringLength(JSVAL_TO_STRING(obj)) == 1)
|
||||
return characterClass;
|
||||
else
|
||||
return stringClass;
|
||||
}
|
||||
/*
|
||||
NAMESPACE do return namespaceClass;
|
||||
COMPOUNDATTRIBUTE do return attributeClass;
|
||||
CLASS do return classClass;
|
||||
METHODCLOSURE do return functionClass;
|
||||
PROTOTYPE do return prototypeClass;
|
||||
INSTANCE do return resolveAlias(o).type;
|
||||
PACKAGE or GLOBAL do return packageClass
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Throw an exception of the specified kind, indicating the position 'pos' and
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "world.h"
|
||||
#include "utilities.h"
|
||||
@ -45,6 +46,8 @@ namespace MetaData {
|
||||
|
||||
|
||||
// forward definitions:
|
||||
class ExecutionState;
|
||||
class JS2Metadata;
|
||||
class JS2Class;
|
||||
class StaticBinding;
|
||||
class Environment;
|
||||
@ -55,6 +58,9 @@ typedef void (Invokable)();
|
||||
typedef Invokable Callor;
|
||||
typedef Invokable Constructor;
|
||||
|
||||
|
||||
enum Phase { CompilePhase, RunPhase };
|
||||
|
||||
class JS2Object {
|
||||
// Every object is either undefined, null, a Boolean,
|
||||
// a number, a string, a namespace, a compound attribute, a class, a method closure,
|
||||
@ -95,12 +101,17 @@ public:
|
||||
bool operator ==(const QualifiedName &b) { return (nameSpace == b.nameSpace) && (id == b.id); }
|
||||
|
||||
Namespace *nameSpace; // The namespace qualifier
|
||||
const StringAtom &id; // The name
|
||||
const StringAtom &id; // The name
|
||||
};
|
||||
|
||||
// MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
|
||||
typedef std::vector<QualifiedName *> Multiname;
|
||||
typedef Multiname::iterator MultinameIterator;
|
||||
typedef std::vector<QualifiedName *> QualifierList;
|
||||
typedef QualifierList::iterator QualifierListIterator;
|
||||
class Multiname {
|
||||
public:
|
||||
QualifierList qList;
|
||||
StringAtom &name;
|
||||
};
|
||||
|
||||
|
||||
class Object_Uninit_Future {
|
||||
@ -364,10 +375,13 @@ public:
|
||||
class FunctionFrame : public Frame {
|
||||
public:
|
||||
Plurality plurality;
|
||||
JS2Object *thisObject; // The value of this; none if this function doesn't define this;
|
||||
// XXX // inaccessible if this function defines this but the value is not
|
||||
// available because this function hasn't been called yet
|
||||
bool prototype; // true if this function is not an instance method but defines this anyway
|
||||
jsval thisObject; // The value of this; none if this function doesn't define this;
|
||||
// inaccessible if this function defines this but the value is not
|
||||
// available because this function hasn't been called yet.
|
||||
|
||||
// Here we use NULL as no this and VOID as inaccessible
|
||||
|
||||
bool prototype; // true if this function is not an instance method but defines this anyway
|
||||
};
|
||||
|
||||
class BlockFrame : public Frame {
|
||||
@ -375,6 +389,14 @@ public:
|
||||
Plurality plurality;
|
||||
};
|
||||
|
||||
|
||||
class LookupKind {
|
||||
public:
|
||||
LookupKind(bool isLexical, jsval thisObject) : isLexical(isLexical), thisObject(thisObject) { }
|
||||
bool isLexical; // if isLexical, use the 'this' below. Otherwise it's a propertyLookup
|
||||
jsval thisObject;
|
||||
};
|
||||
|
||||
// Environments contain the bindings that are visible from a given point in the source code. An ENVIRONMENT is
|
||||
// a list of two or more frames. Each frame corresponds to a scope. More specific frames are listed first
|
||||
// -each frame's scope is directly contained in the following frame's scope. The last frame is always the
|
||||
@ -386,6 +408,13 @@ public:
|
||||
JS2Class *getEnclosingClass();
|
||||
Frame *getRegionalFrame();
|
||||
Frame *getTopFrame() { return firstFrame; }
|
||||
|
||||
jsval findThis(bool allowPrototypeThis);
|
||||
jsval lexicalRead(ExecutionState *eState, Multiname *multiname, Phase phase);
|
||||
|
||||
bool readProperty(ExecutionState *eState, jsval container, Multiname *multinameVal, LookupKind *lookupKind, Phase phase, jsval *rval);
|
||||
|
||||
|
||||
private:
|
||||
Frame *firstFrame;
|
||||
};
|
||||
@ -435,8 +464,6 @@ public:
|
||||
class JS2Metadata {
|
||||
public:
|
||||
|
||||
enum Phase { CompilePhase, RunPhase };
|
||||
|
||||
JS2Metadata(World &world);
|
||||
|
||||
void setCurrentParser(Parser *parser) { mParser = parser; }
|
||||
@ -454,22 +481,47 @@ public:
|
||||
jsval EvalStmtList(Environment *env, Phase phase, StmtNode *p);
|
||||
jsval EvalStmt(Environment *env, Phase phase, StmtNode *p);
|
||||
|
||||
|
||||
JS2Class *objectType(jsval obj);
|
||||
|
||||
void reportError(Exception::Kind kind, const char *message, size_t pos, const char *arg = NULL);
|
||||
void reportError(Exception::Kind kind, const char *message, size_t pos, const String& name);
|
||||
|
||||
|
||||
void initializeMonkey();
|
||||
jsval execute(String *str);
|
||||
jsval execute(String *str, Environment *env, JS2Metadata *meta, size_t pos);
|
||||
|
||||
|
||||
// The one and only 'public' namespace
|
||||
Namespace *publicNamespace; // XXX is this the right place for this ???
|
||||
|
||||
// The base classes:
|
||||
JS2Class *undefinedClass;
|
||||
JS2Class *nullClass;
|
||||
JS2Class *booleanClass;
|
||||
JS2Class *numberClass;
|
||||
JS2Class *characterClass;
|
||||
JS2Class *stringClass;
|
||||
|
||||
|
||||
Parser *mParser; // used for error reporting
|
||||
|
||||
};
|
||||
|
||||
// Captures some metadata-related info. that gets passed back into
|
||||
// js2metadata routines from executing JS code
|
||||
// - it's hidden in the Monkey context private
|
||||
class ExecutionState {
|
||||
public:
|
||||
ExecutionState(JSContext *cx, Environment *env, JS2Metadata *meta, size_t pos) : cx(cx), env(env), meta(meta), pos(pos) { }
|
||||
virtual ~ExecutionState() { }
|
||||
|
||||
JSContext *cx; // the SpiderMonkey context
|
||||
Environment *env; // the frame array, used for lookups
|
||||
JS2Metadata *meta; // base class for error reporting
|
||||
size_t pos; // position from node being executed (vaguely)
|
||||
};
|
||||
|
||||
|
||||
}; // namespace MetaData
|
||||
}; // namespace Javascript
|
||||
Loading…
x
Reference in New Issue
Block a user