зеркало из https://github.com/mozilla/pjs.git
Start on Class definitions.
This commit is contained in:
Родитель
d8b0565933
Коммит
31f1a64820
|
@ -49,6 +49,7 @@ namespace MetaData {
|
|||
|
||||
|
||||
class Multiname;
|
||||
class Frame;
|
||||
|
||||
class BytecodeContainer {
|
||||
public:
|
||||
|
@ -85,8 +86,10 @@ public:
|
|||
static uint16 getShort(void *pc) { return *((uint16 *)pc); }
|
||||
|
||||
void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addShort(mMultinameList.size() - 1); }
|
||||
static Multiname *getMultiname(void *pc){ return (Multiname *)getLong(pc); }
|
||||
|
||||
void addFrame(Frame *f) { mFrameList.push_back(f); addShort(mFrameList.size() - 1); }
|
||||
|
||||
|
||||
void addString(const StringAtom &x, size_t pos) { emitOp(eString, pos); addPointer(&x); }
|
||||
void addString(String &x, size_t pos) { emitOp(eString, pos); addPointer(&x); }
|
||||
void addString(String *x, size_t pos) { emitOp(eString, pos); addPointer(x); }
|
||||
|
@ -97,6 +100,7 @@ public:
|
|||
|
||||
CodeBuffer mBuffer;
|
||||
std::vector<Multiname *> mMultinameList; // gc tracking
|
||||
std::vector<Frame *> mFrameList; // gc tracking
|
||||
|
||||
int32 mStackTop; // keep these as signed so as to
|
||||
int32 mStackMax; // track if they go negative.
|
||||
|
|
|
@ -147,7 +147,7 @@ static int readEvalPrint(FILE *in)
|
|||
metadata->setCurrentParser(&p); // for error reporting
|
||||
|
||||
metadata->ValidateStmtList(parsedStatements);
|
||||
js2val rval = metadata->EvalStmtList(RunPhase, parsedStatements);
|
||||
js2val rval = metadata->ExecuteStmtList(RunPhase, parsedStatements);
|
||||
if (!JS2VAL_IS_VOID(rval))
|
||||
stdOut << *metadata->engine->toString(rval) << '\n';
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ JS2Engine::JS2Engine(World &world)
|
|||
INIT_STRINGATOM(null),
|
||||
INIT_STRINGATOM(undefined),
|
||||
INIT_STRINGATOM(public),
|
||||
INIT_STRINGATOM(private),
|
||||
INIT_STRINGATOM(object)
|
||||
{
|
||||
nanValue = (float64 *)gc_alloc_8();
|
||||
|
@ -245,8 +246,9 @@ int JS2Engine::getStackEffect(JS2Op op)
|
|||
case eMultiname:
|
||||
return 1; // push the multiname object
|
||||
|
||||
case eUse:
|
||||
return -1; // consume a namespace object
|
||||
case ePushFrame:
|
||||
case ePopFrame:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
|
|
|
@ -61,7 +61,8 @@ enum JS2Op {
|
|||
eReturnVoid,
|
||||
eNewObject, // <argCount:16>
|
||||
eMultiname, // <multiname index>
|
||||
eUse,
|
||||
ePushFrame, // <frame index>
|
||||
ePopFrame
|
||||
};
|
||||
|
||||
|
||||
|
@ -111,6 +112,7 @@ public:
|
|||
StringAtom &null_StringAtom;
|
||||
StringAtom &undefined_StringAtom;
|
||||
StringAtom &public_StringAtom;
|
||||
StringAtom &private_StringAtom;
|
||||
StringAtom &object_StringAtom;
|
||||
|
||||
js2val *execStack;
|
||||
|
|
|
@ -71,8 +71,6 @@ namespace MetaData {
|
|||
* Validate the linked list of statement nodes beginning at 'p'
|
||||
*/
|
||||
void JS2Metadata::ValidateStmtList(StmtNode *p) {
|
||||
cxt.openNamespaces.clear();
|
||||
cxt.openNamespaces.push_back(publicNamespace);
|
||||
while (p) {
|
||||
ValidateStmt(&cxt, &env, p);
|
||||
p = p->next;
|
||||
|
@ -192,14 +190,67 @@ namespace MetaData {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case StmtNode::Class:
|
||||
{
|
||||
ClassStmtNode *classStmt = checked_cast<ClassStmtNode *>(p);
|
||||
JS2Class *superClass = objectClass;
|
||||
if (classStmt->superclass) {
|
||||
ValidateExpression(cxt, env, classStmt->superclass);
|
||||
js2val av = EvalExpression(env, CompilePhase, classStmt->superclass);
|
||||
if (JS2VAL_IS_NULL(av) || !JS2VAL_IS_OBJECT(av))
|
||||
reportError(Exception::badValueError, "Class expected in inheritance", p->pos);
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(av);
|
||||
if (obj->kind != ClassKind)
|
||||
reportError(Exception::badValueError, "Class expected in inheritance", p->pos);
|
||||
superClass = checked_cast<JS2Class *>(obj);
|
||||
}
|
||||
Attribute *attr = NULL;
|
||||
if (classStmt->attributes) {
|
||||
ValidateAttributeExpression(cxt, env, classStmt->attributes);
|
||||
attr = EvalAttributeExpression(env, CompilePhase, classStmt->attributes);
|
||||
}
|
||||
CompoundAttribute *a = Attribute::toCompoundAttribute(attr);
|
||||
if (!superClass->complete || superClass->final)
|
||||
reportError(Exception::definitionError, "Illegal inheritance", p->pos);
|
||||
JS2Object *proto = NULL;
|
||||
bool final;
|
||||
switch (a->memberMod) {
|
||||
case Attribute::NoModifier:
|
||||
final = false;
|
||||
break;
|
||||
case Attribute::Static:
|
||||
if (env->getTopFrame()->kind != ClassKind)
|
||||
reportError(Exception::definitionError, "Illegal use of static modifier", p->pos);
|
||||
final = false;
|
||||
break;
|
||||
case Attribute::Final:
|
||||
final = true;
|
||||
break;
|
||||
default:
|
||||
reportError(Exception::definitionError, "Illegal modifier for class definition", p->pos);
|
||||
break;
|
||||
}
|
||||
JS2Class *c = new JS2Class(superClass, proto, new Namespace(engine->public_StringAtom), (a->dynamic || superClass->dynamic), final);
|
||||
classStmt->c = c;
|
||||
Variable *v = new Variable(classClass, OBJECT_TO_JS2VAL(c), true);
|
||||
defineStaticMember(env, classStmt->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
|
||||
if (classStmt->body) {
|
||||
env->addFrame(c);
|
||||
ValidateStmtList(cxt, env, classStmt->body->statements);
|
||||
ASSERT(env->getTopFrame() == c);
|
||||
env->removeTopFrame();
|
||||
}
|
||||
c->complete = true;
|
||||
}
|
||||
} // switch (p->getKind())
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Evaluate the linked list of statement nodes beginning at 'p' (generate bytecode)
|
||||
* and then execute that bytecode
|
||||
* Evaluate the linked list of statement nodes beginning at 'p'
|
||||
* (generate bytecode and then execute that bytecode
|
||||
*/
|
||||
js2val JS2Metadata::EvalStmtList(Phase phase, StmtNode *p)
|
||||
js2val JS2Metadata::ExecuteStmtList(Phase phase, StmtNode *p)
|
||||
{
|
||||
BytecodeContainer *saveBacon = bCon;
|
||||
bCon = new BytecodeContainer();
|
||||
|
@ -267,6 +318,25 @@ namespace MetaData {
|
|||
{
|
||||
}
|
||||
break;
|
||||
case StmtNode::Class:
|
||||
{
|
||||
ClassStmtNode *classStmt = checked_cast<ClassStmtNode *>(p);
|
||||
JS2Class *c = classStmt->c;
|
||||
if (classStmt->body) {
|
||||
env->addFrame(c);
|
||||
bCon->emitOp(ePushFrame, p->pos);
|
||||
bCon->addFrame(c);
|
||||
StmtNode *bp = classStmt->body->statements;
|
||||
while (bp) {
|
||||
EvalStmt(env, phase, bp);
|
||||
bp = bp->next;
|
||||
}
|
||||
ASSERT(env->getTopFrame() == c);
|
||||
env->removeTopFrame();
|
||||
bCon->emitOp(ePopFrame, p->pos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
} // switch (p->getKind())
|
||||
|
@ -970,6 +1040,8 @@ namespace MetaData {
|
|||
glob(world),
|
||||
env(new MetaData::SystemFrame(), &glob)
|
||||
{
|
||||
cxt.openNamespaces.clear();
|
||||
cxt.openNamespaces.push_back(publicNamespace);
|
||||
}
|
||||
|
||||
// objectType(o) returns an OBJECT o's most specific type.
|
||||
|
@ -1365,6 +1437,27 @@ namespace MetaData {
|
|||
nextPond->moveUnmarkedToFreeList();
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* JS2Class
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
JS2Class::JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final)
|
||||
: Frame(ClassKind),
|
||||
instanceInitOrder(NULL),
|
||||
complete(false),
|
||||
super(super),
|
||||
prototype(proto),
|
||||
privateNamespace(privateNamespace),
|
||||
dynamic(dynamic),
|
||||
primitive(false),
|
||||
final(final),
|
||||
call(NULL),
|
||||
construct(NULL)
|
||||
{ }
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* JS2Object
|
||||
|
|
|
@ -353,7 +353,7 @@ public:
|
|||
|
||||
class JS2Class : public Frame {
|
||||
public:
|
||||
JS2Class() : Frame(ClassKind) { }
|
||||
JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final);
|
||||
|
||||
StringAtom &getName();
|
||||
|
||||
|
@ -559,6 +559,9 @@ public:
|
|||
Frame *getTopFrame() { return firstFrame; }
|
||||
Frame *getPackageOrGlobalFrame();
|
||||
|
||||
void addFrame(Frame *f) { f->nextFrame = firstFrame; firstFrame = f; }
|
||||
void removeTopFrame() { firstFrame = firstFrame->nextFrame; }
|
||||
|
||||
js2val findThis(bool allowPrototypeThis);
|
||||
js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
|
||||
|
@ -629,7 +632,7 @@ public:
|
|||
void ValidateExpression(Context *cxt, Environment *env, ExprNode *p);
|
||||
void ValidateAttributeExpression(Context *cxt, Environment *env, ExprNode *p);
|
||||
|
||||
js2val EvalStmtList(Environment *env, Phase phase, StmtNode *p);
|
||||
js2val ExecuteStmtList(Phase phase, StmtNode *p);
|
||||
js2val EvalExpression(Environment *env, Phase phase, ExprNode *p);
|
||||
Reference *EvalExprNode(Environment *env, Phase phase, ExprNode *p);
|
||||
Attribute *EvalAttributeExpression(Environment *env, Phase phase, ExprNode *p);
|
||||
|
@ -680,6 +683,7 @@ public:
|
|||
JS2Class *stringClass;
|
||||
JS2Class *objectClass;
|
||||
JS2Class *namespaceClass;
|
||||
JS2Class *classClass;
|
||||
|
||||
Parser *mParser; // used for error reporting
|
||||
|
||||
|
|
|
@ -33,62 +33,49 @@
|
|||
|
||||
// Get a multiname literal and add the currently open namespaces from the context
|
||||
// Push the resulting multiname object
|
||||
case eMultiname: {
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
push(OBJECT_TO_JS2VAL(mn));
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
// Get a multiname literal and pop a namespace value to add to it
|
||||
// Push the resulting multiname object
|
||||
case eQMultiname: {
|
||||
js2val nsVal = pop();
|
||||
if (!JS2VAL_IS_OBJECT(nsVal))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos);
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(nsVal);
|
||||
if ((obj->kind != AttributeObjectKind) || ((checked_cast<Attribute *>(obj))->attrKind != Attribute::NamespaceAttr))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos);
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(checked_cast<Namespace *>(obj));
|
||||
push(OBJECT_TO_JS2VAL(mn));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case eMultiname:
|
||||
{
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
push(OBJECT_TO_JS2VAL(mn));
|
||||
}
|
||||
break;
|
||||
|
||||
// Pop a multiname object and read it's value from the environment on to the stack.
|
||||
case eLexicalRead: {
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
retval = meta->env.lexicalRead(meta, mn, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
case eLexicalRead:
|
||||
{
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
retval = meta->env.lexicalRead(meta, mn, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
// Pop a value and a multiname. Write the value to the multiname in the environment, leave
|
||||
// the value on the stack top.
|
||||
case eLexicalWrite: {
|
||||
retval = pop();
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
case eLexicalWrite:
|
||||
{
|
||||
retval = pop();
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
// Pop a namespace object and add it to the list of currently open namespaces in the context
|
||||
case eUse: {
|
||||
js2val nsVal = pop();
|
||||
if (!JS2VAL_IS_OBJECT(nsVal))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->errorPos());
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(nsVal);
|
||||
if ((obj->kind != AttributeObjectKind) || ((checked_cast<Attribute *>(obj))->attrKind != Attribute::NamespaceAttr))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->errorPos());
|
||||
case ePushFrame:
|
||||
{
|
||||
Frame *f = bCon->mFrameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
case ePopFrame:
|
||||
{
|
||||
}
|
||||
break;
|
|
@ -59,6 +59,7 @@ namespace JavaScript {
|
|||
#ifdef EPIMETHEUS
|
||||
namespace MetaData {
|
||||
class Context;
|
||||
class JS2Class;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -678,7 +679,9 @@ namespace JavaScript {
|
|||
#ifdef DIKDIK
|
||||
JS2Runtime::JSType *mType; // used by backend
|
||||
#endif
|
||||
|
||||
#ifdef EPIMETHEUS
|
||||
MetaData::JS2Class *c;
|
||||
#endif
|
||||
ClassStmtNode(size_t pos, ExprNode *attributes, const StringAtom &name, ExprNode *superclass, BlockStmtNode *body):
|
||||
NamespaceStmtNode(pos, Class, attributes, name), superclass(superclass), body(body) {}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче