Split some functionality into js2eval from js2metadata. Began fix for typed

var initialization.
This commit is contained in:
rogerl%netscape.com 2003-01-31 05:24:38 +00:00
Родитель 91b818b389
Коммит 46dbeba3c6
5 изменённых файлов: 258 добавлений и 184 удалений

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

@ -99,6 +99,7 @@ enum JS2Op {
eLexicalRead, // <multiname index:u16>
eLexicalWrite, // <multiname index:u16>
eLexicalInit, // <multiname index:u16>
eLexicalRef, // <multiname index:u16>
eLexicalDelete, // <multiname index:u16>
eDotRead, // <multiname index:u16>

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

@ -36,10 +36,166 @@
#include "msvc_pragma.h"
#endif
#include <algorithm>
#include <assert.h>
#include <map>
#include <list>
#include <stack>
#include "world.h"
#include "utilities.h"
#include "js2value.h"
#include "jslong.h"
#include "numerics.h"
#include "reader.h"
#include "parser.h"
#include "regexp.h"
#include "js2engine.h"
#include "bytecodecontainer.h"
#include "js2metadata.h"
namespace JavaScript {
namespace MetaData {
js2val JS2Metadata::readEvalString(const String &str, const String& fileName)
{
js2val result = JS2VAL_VOID;
Arena a;
Pragma::Flags flags = Pragma::es4;
Parser p(world, a, flags, str, fileName);
CompilationData *oldData = NULL;
try {
StmtNode *parsedStatements = p.parseProgram();
ASSERT(p.lexer.peek(true).hasKind(Token::end));
if (showTrees)
{
PrettyPrinter f(stdOut, 80);
{
PrettyPrinter::Block b(f, 2);
f << "Program =";
f.linearBreak(1);
StmtNode::printStatements(f, parsedStatements);
}
f.end();
stdOut << '\n';
}
if (parsedStatements) {
oldData = startCompilationUnit(NULL, str, fileName);
ValidateStmtList(parsedStatements);
result = ExecuteStmtList(RunPhase, parsedStatements);
}
}
catch (Exception &x) {
if (oldData)
restoreCompilationUnit(oldData);
throw x;
}
if (oldData)
restoreCompilationUnit(oldData);
return result;
}
js2val JS2Metadata::readEvalFile(const String& fileName)
{
String buffer;
int ch;
js2val result = JS2VAL_VOID;
std::string str(fileName.length(), char());
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
FILE* f = fopen(str.c_str(), "r");
if (f) {
while ((ch = getc(f)) != EOF)
buffer += static_cast<char>(ch);
fclose(f);
result = readEvalString(buffer, fileName);
}
return result;
}
js2val JS2Metadata::readEvalFile(const char *fileName)
{
String buffer;
int ch;
js2val result = JS2VAL_VOID;
FILE* f = fopen(fileName, "r");
if (f) {
while ((ch = getc(f)) != EOF)
buffer += static_cast<char>(ch);
fclose(f);
result = readEvalString(buffer, widenCString(fileName));
}
return result;
}
/*
* Evaluate the linked list of statement nodes beginning at 'p'
* (generate bytecode and then execute that bytecode
*/
js2val JS2Metadata::ExecuteStmtList(Phase phase, StmtNode *p)
{
size_t lastPos = p->pos;
while (p) {
SetupStmt(env, phase, p);
lastPos = p->pos;
p = p->next;
}
bCon->emitOp(eReturnVoid, lastPos);
uint8 *savePC = engine->pc;
engine->pc = NULL;
js2val retval = engine->interpret(phase, bCon);
engine->pc = savePC;
return retval;
}
/*
* Evaluate an expression 'p' AND execute the associated bytecode
*/
js2val JS2Metadata::EvalExpression(Environment *env, Phase phase, ExprNode *p)
{
js2val retval;
uint8 *savePC = NULL;
JS2Class *exprType;
CompilationData *oldData = startCompilationUnit(NULL, bCon->mSource, bCon->mSourceLocation);
try {
Reference *r = SetupExprNode(env, phase, p, &exprType);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eReturn, p->pos);
savePC = engine->pc;
engine->pc = NULL;
retval = engine->interpret(phase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
return retval;
}
// Execute an expression and return the result, which must be a type
JS2Class *JS2Metadata::EvalTypeExpression(Environment *env, Phase phase, ExprNode *p)
{
js2val retval = EvalExpression(env, phase, p);
if (JS2VAL_IS_PRIMITIVE(retval))
reportError(Exception::badValueError, "Type expected", p->pos);
JS2Object *obj = JS2VAL_TO_OBJECT(retval);
if (obj->kind != ClassKind)
reportError(Exception::badValueError, "Type expected", p->pos);
return checked_cast<JS2Class *>(obj);
}
}; // namespace MetaData
}; // namespace Javascript

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

@ -59,83 +59,6 @@
namespace JavaScript {
namespace MetaData {
inline char narrow(char16 ch) { return char(ch); }
js2val JS2Metadata::readEvalString(const String &str, const String& fileName)
{
js2val result = JS2VAL_VOID;
Arena a;
Pragma::Flags flags = Pragma::es4;
Parser p(world, a, flags, str, fileName);
CompilationData *oldData = NULL;
try {
StmtNode *parsedStatements = p.parseProgram();
ASSERT(p.lexer.peek(true).hasKind(Token::end));
if (showTrees)
{
PrettyPrinter f(stdOut, 80);
{
PrettyPrinter::Block b(f, 2);
f << "Program =";
f.linearBreak(1);
StmtNode::printStatements(f, parsedStatements);
}
f.end();
stdOut << '\n';
}
if (parsedStatements) {
oldData = startCompilationUnit(NULL, str, fileName);
ValidateStmtList(parsedStatements);
result = ExecuteStmtList(RunPhase, parsedStatements);
}
}
catch (Exception &x) {
if (oldData)
restoreCompilationUnit(oldData);
throw x;
}
if (oldData)
restoreCompilationUnit(oldData);
return result;
}
js2val JS2Metadata::readEvalFile(const String& fileName)
{
String buffer;
int ch;
js2val result = JS2VAL_VOID;
std::string str(fileName.length(), char());
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
FILE* f = fopen(str.c_str(), "r");
if (f) {
while ((ch = getc(f)) != EOF)
buffer += static_cast<char>(ch);
fclose(f);
result = readEvalString(buffer, fileName);
}
return result;
}
js2val JS2Metadata::readEvalFile(const char *fileName)
{
String buffer;
int ch;
js2val result = JS2VAL_VOID;
FILE* f = fopen(fileName, "r");
if (f) {
while ((ch = getc(f)) != EOF)
buffer += static_cast<char>(ch);
fclose(f);
result = readEvalString(buffer, widenCString(fileName));
}
return result;
}
/************************************************************************************
@ -523,7 +446,7 @@ namespace MetaData {
}
else {
Variable *v = new Variable(functionClass, OBJECT_TO_JS2VAL(fObj), true);
vb->mn = defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
}
}
}
@ -544,7 +467,7 @@ namespace MetaData {
ASSERT(!prototype); // XXX right?
JS2Object *fObj = validateStaticFunction(f, compileThis, prototype, unchecked, cxt, env);
ConstructorMethod *cm = new ConstructorMethod(OBJECT_TO_JS2VAL(fObj));
vb->mn = defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, cm, p->pos);
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, cm, p->pos);
}
break;
}
@ -723,26 +646,6 @@ namespace MetaData {
}
/*
* Evaluate the linked list of statement nodes beginning at 'p'
* (generate bytecode and then execute that bytecode
*/
js2val JS2Metadata::ExecuteStmtList(Phase phase, StmtNode *p)
{
size_t lastPos = p->pos;
while (p) {
SetupStmt(env, phase, p);
lastPos = p->pos;
p = p->next;
}
bCon->emitOp(eReturnVoid, lastPos);
uint8 *savePC = engine->pc;
engine->pc = NULL;
js2val retval = engine->interpret(phase, bCon);
engine->pc = savePC;
return retval;
}
JS2Class *JS2Metadata::getVariableType(Variable *v, Phase phase, size_t pos)
{
JS2Class *type = v->type;
@ -1245,13 +1148,13 @@ namespace MetaData {
bCon->emitOp(eCoerce, p->pos);
bCon->addType(v->type);
LexicalReference *lVal = new LexicalReference(vb->mn, cxt.strict);
lVal->emitWriteBytecode(bCon, p->pos);
lVal->emitInitBytecode(bCon, p->pos);
bCon->emitOp(ePop, p->pos);
}
else {
v->type->emitDefaultValue(bCon, p->pos);
LexicalReference *lVal = new LexicalReference(vb->mn, cxt.strict);
lVal->emitWriteBytecode(bCon, p->pos);
lVal->emitInitBytecode(bCon, p->pos);
bCon->emitOp(ePop, p->pos);
}
}
@ -1760,34 +1663,6 @@ namespace MetaData {
/*
* Evaluate an expression 'p' AND execute the associated bytecode
*/
js2val JS2Metadata::EvalExpression(Environment *env, Phase phase, ExprNode *p)
{
js2val retval;
uint8 *savePC = NULL;
JS2Class *exprType;
CompilationData *oldData = startCompilationUnit(NULL, bCon->mSource, bCon->mSourceLocation);
try {
Reference *r = SetupExprNode(env, phase, p, &exprType);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eReturn, p->pos);
savePC = engine->pc;
engine->pc = NULL;
retval = engine->interpret(phase, bCon);
}
catch (Exception &x) {
engine->pc = savePC;
restoreCompilationUnit(oldData);
throw x;
}
engine->pc = savePC;
restoreCompilationUnit(oldData);
return retval;
}
/*
* Process the expression (i.e. generate bytecode, but don't execute) rooted at p.
*/
@ -2384,18 +2259,6 @@ doUnary:
return returnRef;
}
// Execute an expression and return the result, which must be a type
JS2Class *JS2Metadata::EvalTypeExpression(Environment *env, Phase phase, ExprNode *p)
{
js2val retval = EvalExpression(env, phase, p);
if (JS2VAL_IS_PRIMITIVE(retval))
reportError(Exception::badValueError, "Type expected", p->pos);
JS2Object *obj = JS2VAL_TO_OBJECT(retval);
if (obj->kind != ClassKind)
reportError(Exception::badValueError, "Type expected", p->pos);
return checked_cast<JS2Class *>(obj);
}
/************************************************************************************
*
* Environment
@ -2493,6 +2356,27 @@ doUnary:
meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name);
}
// Attempt the write in the top frame in the current environment - if the property
// exists, then fine. Otherwise create the property there.
void Environment::lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase)
{
LookupKind lookup(true, findThis(false));
FrameListIterator fi = getBegin();
while (fi != getEnd()) {
if (meta->writeProperty(*fi, multiname, &lookup, false, newValue, phase))
return;
fi++;
}
if (createIfMissing) {
Frame *pf = getPackageOrGlobalFrame();
if (pf->kind == GlobalObjectKind) {
if (meta->writeProperty(pf, multiname, &lookup, true, newValue, phase))
return;
}
}
meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name);
}
// Delete the named property in the current environment, return true if the property
// can't be found, or the result of the deleteProperty call if it was found.
bool Environment::lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase)
@ -2580,7 +2464,7 @@ doUnary:
************************************************************************************/
// return true if the given namespace is on the namespace list
bool Multiname::onList(Namespace *nameSpace)
bool Multiname::listContains(Namespace *nameSpace)
{
if (nsList.empty())
return true;
@ -2641,6 +2525,7 @@ doUnary:
}
Multiname *mn = new Multiname(id);
mn->addNamespace(namespaces);
// Search the local frame for an overlapping definition
LocalBindingIterator b, end;
if (access & ReadAccess) {
for (b = localFrame->localReadBindings.lower_bound(*id),
@ -2660,40 +2545,32 @@ doUnary:
// Check all frames below the current - up to the RegionalFrame - for a non-forbidden definition
Frame *regionalFrame = *(env->getRegionalFrame());
if (localFrame != regionalFrame) {
// The frame iterator is pointing at the top of the environment's
// frame list, start at the one below that and continue to the frame
// returned by 'getRegionalFrame()'.
Frame *fr = *++fi;
while (true) {
for (b = fr->localReadBindings.lower_bound(*id),
end = fr->localReadBindings.upper_bound(*id); (b != end); b++) {
if (mn->matches(b->second->qname) && (b->second->content->kind != LocalMember::Forbidden))
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
}
if (fr == regionalFrame)
break;
fr = *++fi;
}
fi = env->getBegin();
fr = *++fi;
while (true) {
for (b = fr->localWriteBindings.lower_bound(*id),
end = fr->localWriteBindings.upper_bound(*id); (b != end); b++) {
if (mn->matches(b->second->qname) && (b->second->content->kind != LocalMember::Forbidden))
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
if (access & ReadAccess) {
for (b = fr->localReadBindings.lower_bound(*id),
end = fr->localReadBindings.upper_bound(*id); (b != end); b++) {
if (mn->matches(b->second->qname) && (b->second->content->kind != LocalMember::Forbidden))
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
}
}
if (access & WriteAccess) {
for (b = fr->localWriteBindings.lower_bound(*id),
end = fr->localWriteBindings.upper_bound(*id); (b != end); b++) {
if (mn->matches(b->second->qname) && (b->second->content->kind != LocalMember::Forbidden))
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
}
}
if (fr == regionalFrame)
break;
fr = *++fi;
ASSERT(fr);
}
}
// If the regional frame is the global object, make sure there's not a dynamic
// property with the same id as the one we're about to define
if (regionalFrame->kind == GlobalObjectKind) {
GlobalObject *gObj = checked_cast<GlobalObject *>(regionalFrame);
DynamicPropertyIterator dp = gObj->dynamicProperties.find(*id);
if (dp != gObj->dynamicProperties.end())
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
}
// Now insert the id, via all it's namespaces into the local frame
for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) {
QualifiedName qName(*nli, id);
@ -2705,23 +2582,47 @@ doUnary:
localFrame->localWriteBindings.insert(e);
}
// And mark all (any) lower definitions as Forbidden
// XXX there's a discrepancy in the spec. -- the comment says:
// "Mark the bindings of multiname as Forbidden in all non-innermost frames in the current
// region if they haven't been marked as such already"
// But the code simply adds a Forbidden binding in each namespace to each frame in the region
// Mark the bindings of multiname as Forbidden in all non-innermost frames in the current
// region if they haven't been marked as such already.
if (localFrame != regionalFrame) {
fi = env->getBegin();
Frame *fr = *++fi;
while (true) {
for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) {
QualifiedName qName(*nli, id);
LocalBinding *sb = new LocalBinding(qName, forbiddenMember);
const LocalBindingMap::value_type e(*id, sb);
if (access & ReadAccess)
fr->localReadBindings.insert(e);
if (access & WriteAccess)
fr->localWriteBindings.insert(e);
if (access & ReadAccess) {
bool foundEntry = false;
for (b = fr->localReadBindings.lower_bound(*id),
end = fr->localReadBindings.upper_bound(*id); (b != end); b++) {
if (b->second->qname.nameSpace == *nli) {
ASSERT(b->second->content->kind == LocalMember::Forbidden);
foundEntry = true;
break;
}
}
if (!foundEntry) {
QualifiedName qName(*nli, id);
LocalBinding *sb = new LocalBinding(qName, forbiddenMember);
const LocalBindingMap::value_type e(*id, sb);
fr->localReadBindings.insert(e);
}
}
if (access & WriteAccess) {
bool foundEntry = false;
for (b = fr->localWriteBindings.lower_bound(*id),
end = fr->localWriteBindings.upper_bound(*id); (b != end); b++) {
if (b->second->qname.nameSpace == *nli) {
ASSERT(b->second->content->kind == LocalMember::Forbidden);
foundEntry = true;
break;
}
}
if (!foundEntry) {
QualifiedName qName(*nli, id);
LocalBinding *sb = new LocalBinding(qName, forbiddenMember);
const LocalBindingMap::value_type e(*id, sb);
fr->localWriteBindings.insert(e);
}
}
}
if (fr == regionalFrame)
break;
@ -3313,7 +3214,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
ASSERT(container && ((container->kind == SimpleInstanceKind)
|| (container->kind == GlobalObjectKind)
|| (container->kind == PrototypeInstanceKind)));
if (!multiname->onList(publicNamespace))
if (!multiname->listContains(publicNamespace))
return false;
const String *name = multiname->name;
if (phase == CompilePhase)
@ -3385,7 +3286,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
ASSERT(container && ((container->kind == SimpleInstanceKind)
|| (container->kind == GlobalObjectKind)
|| (container->kind == PrototypeInstanceKind)));
if (!multiname->onList(publicNamespace))
if (!multiname->listContains(publicNamespace))
return false;
const String *name = multiname->name;
DynamicPropertyMap *dMap = NULL;
@ -3813,7 +3714,7 @@ deleteClassProperty:
ASSERT(container && ((container->kind == SimpleInstanceKind)
|| (container->kind == GlobalObjectKind)
|| (container->kind == PrototypeInstanceKind)));
if (!multiname->onList(publicNamespace))
if (!multiname->listContains(publicNamespace))
return false;
const String *name = multiname->name;
DynamicPropertyMap *dMap = NULL;

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

@ -241,8 +241,8 @@ public:
void addNamespace(NamespaceList *ns);
void addNamespace(Context &cxt);
bool matches(QualifiedName &q) { return (*name == *q.id) && onList(q.nameSpace); }
bool onList(Namespace *nameSpace);
bool matches(QualifiedName &q) { return (*name == *q.id) && listContains(q.nameSpace); }
bool listContains(Namespace *nameSpace);
NamespaceList nsList;
const String *name;
@ -754,6 +754,7 @@ public:
Environment *env; // The environment in which the reference was created.
bool strict; // The strict setting from the context in effect at the point where the reference was created
void emitInitBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalInit, pos); bCon->addMultiname(variableMultiname); }
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalRead, pos); bCon->addMultiname(variableMultiname); }
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalWrite, pos); bCon->addMultiname(variableMultiname); }
@ -941,6 +942,7 @@ public:
js2val findThis(bool allowPrototypeThis);
js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase);
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
bool lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase);
void instantiateFrame(Frame *pluralFrame, Frame *singularFrame);
@ -1175,6 +1177,9 @@ public:
};
inline char narrow(char16 ch) { return char(ch); }
}; // namespace MetaData
}; // namespace Javascript

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

@ -113,6 +113,17 @@
}
break;
// Write the top value to the multiname in the environment, leave
// the value on the stack top.
case eLexicalInit:
{
a = top();
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalInit(meta, mn, a, true, phase);
}
break;
// Construct a reference pair consisting of a NULL base and the read value
case eLexicalRef:
{