incremental

git-svn-id: svn://10.0.0.236/trunk@126277 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rogerl%netscape.com 2002-08-03 23:25:14 +00:00
parent a99f9fc6ea
commit 4736214ba3
4 changed files with 282 additions and 75 deletions

View File

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

View File

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

View File

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

View File

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