зеркало из https://github.com/mozilla/gecko-dev.git
DefineStaticMember & multiname changes
This commit is contained in:
Родитель
8505058394
Коммит
016eae89e3
|
@ -224,6 +224,7 @@ int JS2Engine::getStackEffect(JS2Op op)
|
|||
case eReturn:
|
||||
case ePlus:
|
||||
return -1;
|
||||
|
||||
case eString:
|
||||
case eTrue:
|
||||
case eFalse:
|
||||
|
@ -231,13 +232,18 @@ int JS2Engine::getStackEffect(JS2Op op)
|
|||
return 1;
|
||||
|
||||
case eLexicalRead:
|
||||
return 0;
|
||||
return 0; // consumes a multiname, pushes the value
|
||||
case eLexicalWrite:
|
||||
return -1;
|
||||
return -2; // consumes a multiname and the value
|
||||
|
||||
case eReturnVoid:
|
||||
return 0;
|
||||
|
||||
case eMultiname:
|
||||
case eQMultiname:
|
||||
return 1; // push the multiname object
|
||||
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
|
|
@ -55,11 +55,13 @@ enum JS2Op {
|
|||
eNumber,
|
||||
eString, // <string pointer>
|
||||
eObject, // <named argument count>
|
||||
eLexicalRead, // <multiname index>
|
||||
eLexicalWrite, // <multiname index>
|
||||
eLexicalRead,
|
||||
eLexicalWrite,
|
||||
eReturn,
|
||||
eReturnVoid,
|
||||
eNewObject // <argCount:16>
|
||||
eNewObject, // <argCount:16>
|
||||
eMultiname, // <multiname index>
|
||||
eQMultiname, // <multiname index>
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -154,6 +154,20 @@ namespace MetaData {
|
|||
ValidateExpression(cxt, env, e->expr);
|
||||
}
|
||||
break;
|
||||
case StmtNode::Namespace:
|
||||
{
|
||||
NamespaceStmtNode *ns = checked_cast<NamespaceStmtNode *>(p);
|
||||
ValidateAttributeExpression(cxt, env, ns->attributes);
|
||||
Attribute *attr = EvalAttributeExpression(env, CompilePhase, ns->attributes);
|
||||
CompoundAttribute *a = Attribute::toCompoundAttribute(attr);
|
||||
if (a->dynamic || a->prototype)
|
||||
reportError(Exception::definitionError, "Illegal attribute", p->pos);
|
||||
if ( ! ((a->memberMod == Attribute::NoModifier) || ((a->memberMod == Attribute::Static) && (env->getTopFrame()->kind == ClassKind))) )
|
||||
reportError(Exception::definitionError, "Illegal attribute", p->pos);
|
||||
Variable *v = new Variable(namespaceClass, OBJECT_TO_JS2VAL(new Namespace(ns->name)), true);
|
||||
env->defineStaticMember(this, ns->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v);
|
||||
}
|
||||
break;
|
||||
} // switch (p->getKind())
|
||||
}
|
||||
|
||||
|
@ -215,6 +229,10 @@ namespace MetaData {
|
|||
if (r) r->emitReadBytecode(bCon);
|
||||
}
|
||||
break;
|
||||
case StmtNode::Namespace:
|
||||
{
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
} // switch (p->getKind())
|
||||
|
@ -293,7 +311,7 @@ namespace MetaData {
|
|||
{
|
||||
BinaryExprNode *j = checked_cast<BinaryExprNode *>(p);
|
||||
Attribute *a = EvalAttributeExpression(env, phase, j->op1);
|
||||
if (a && (a->kind == Attribute::FalseKind))
|
||||
if (a && (a->attrKind == Attribute::FalseAttr))
|
||||
return a;
|
||||
Attribute *b = EvalAttributeExpression(env, phase, j->op2);
|
||||
try {
|
||||
|
@ -352,25 +370,25 @@ namespace MetaData {
|
|||
// a is not false
|
||||
Attribute *Attribute::combineAttributes(Attribute *a, Attribute *b)
|
||||
{
|
||||
if (b && (b->kind == FalseKind)) {
|
||||
if (b && (b->attrKind == FalseAttr)) {
|
||||
if (a) delete a;
|
||||
return b;
|
||||
}
|
||||
if (!a || (a->kind == TrueKind)) {
|
||||
if (!a || (a->attrKind == TrueAttr)) {
|
||||
if (a) delete a;
|
||||
return b;
|
||||
}
|
||||
if (!b || (b->kind == TrueKind)) {
|
||||
if (!b || (b->attrKind == TrueAttr)) {
|
||||
if (b) delete b;
|
||||
return a;
|
||||
}
|
||||
if (a->kind == NamespaceKind) {
|
||||
if (a->attrKind == NamespaceAttr) {
|
||||
if (a == b) {
|
||||
delete b;
|
||||
return a;
|
||||
}
|
||||
Namespace *na = checked_cast<Namespace *>(a);
|
||||
if (b->kind == NamespaceKind) {
|
||||
if (b->kind == NamespaceAttr) {
|
||||
Namespace *nb = checked_cast<Namespace *>(b);
|
||||
CompoundAttribute *c = new CompoundAttribute();
|
||||
c->addNamespace(na);
|
||||
|
@ -380,7 +398,7 @@ namespace MetaData {
|
|||
return (Attribute *)c;
|
||||
}
|
||||
else {
|
||||
ASSERT(b->kind == CompoundKind);
|
||||
ASSERT(b->attrKind == CompoundAttr);
|
||||
CompoundAttribute *cb = checked_cast<CompoundAttribute *>(b);
|
||||
cb->addNamespace(na);
|
||||
delete a;
|
||||
|
@ -389,7 +407,7 @@ namespace MetaData {
|
|||
}
|
||||
else {
|
||||
// Both a and b are compound attributes. Ensure that they have no conflicting contents.
|
||||
ASSERT((a->kind == CompoundKind) && (b->kind == CompoundKind));
|
||||
ASSERT((a->attrKind == CompoundAttr) && (b->attrKind == CompoundAttr));
|
||||
CompoundAttribute *ca = checked_cast<CompoundAttribute *>(a);
|
||||
CompoundAttribute *cb = checked_cast<CompoundAttribute *>(b);
|
||||
if ((ca->memberMod != NoModifier) && (cb->memberMod != NoModifier) && (ca->memberMod != cb->memberMod))
|
||||
|
@ -420,7 +438,7 @@ namespace MetaData {
|
|||
namespaces->push_back(n);
|
||||
}
|
||||
|
||||
CompoundAttribute::CompoundAttribute() : Attribute(CompoundKind),
|
||||
CompoundAttribute::CompoundAttribute() : Attribute(CompoundAttr),
|
||||
namespaces(NULL), xplicit(false), dynamic(false), memberMod(NoModifier),
|
||||
overrideMod(NoOverride), prototype(false), unused(false)
|
||||
{
|
||||
|
@ -551,9 +569,8 @@ namespace MetaData {
|
|||
{
|
||||
QualifyExprNode *qe = checked_cast<QualifyExprNode *>(p);
|
||||
const StringAtom &name = checked_cast<IdentifierExprNode *>(p)->name;
|
||||
const StringAtom &qualifierName = checked_cast<IdentifierExprNode *>(qe->qualifier)->name;
|
||||
|
||||
returnRef = new LexicalReference(i->name, cxt.strict);
|
||||
EvalExprNode(env, phase, qe->qualifier);
|
||||
returnRef = new LexicalReference(name, cxt.strict, true);
|
||||
}
|
||||
break;
|
||||
case ExprNode::identifier:
|
||||
|
@ -606,6 +623,7 @@ namespace MetaData {
|
|||
if (b->op2->getKind() == ExprNode::qualify) {
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
|
@ -713,6 +731,58 @@ namespace MetaData {
|
|||
meta->reportError(Exception::referenceError, "{0} is undefined", meta->errorPos, multiname->name);
|
||||
}
|
||||
|
||||
void Environment::defineStaticMember(JS2Metadata *meta, const StringAtom &id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m)
|
||||
{
|
||||
NamespaceList publicNamespaceList;
|
||||
|
||||
Frame *localFrame = firstFrame;
|
||||
if ((overrideMod != Attribute::NoOverride) || (xplicit && localFrame->kind != PackageKind))
|
||||
meta->reportError(Exception::definitionError, "Illegal definition", meta->errorPos);
|
||||
if (namespaces->empty()) {
|
||||
publicNamespaceList.push_back(meta->publicNamespace);
|
||||
namespaces = &publicNamespaceList;
|
||||
}
|
||||
Multiname *mn = new Multiname(id, true);
|
||||
mn->addNamespace(namespaces);
|
||||
|
||||
|
||||
for (StaticBindingIterator b = localFrame->staticReadBindings.lower_bound(id),
|
||||
end = localFrame->staticReadBindings.upper_bound(id); (b != end); b++) {
|
||||
if (b->second->qname == qName)
|
||||
reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id);
|
||||
}
|
||||
|
||||
|
||||
Frame *regionalFrame = getRegionalFrame();
|
||||
Frame *fr = firstFrame->nextFrame;
|
||||
while (true) {
|
||||
for (b = fr->staticReadBindings.lower_bound(id),
|
||||
end = fr->staticReadBindings.upper_bound(id); (b != end); b++) {
|
||||
if ((b->second->qname == qName) && (b->second->content->kind != Forbidden))
|
||||
reportError(Exception::definitionError, "Duplicate definition {0}", p->pos, id);
|
||||
}
|
||||
fr = fr->nextFrame;
|
||||
if (fr == regionalFrame) break;
|
||||
}
|
||||
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}", p->pos, id);
|
||||
}
|
||||
|
||||
for (NamespaceListIterator nli = mn->nsList.begin(), end = mn->nsList.end(); (nli != end); nli++) {
|
||||
QualifiedName qName(*nli, id);
|
||||
StaticBinding *sb = new StaticBinding(qName, new HoistedVar());
|
||||
const StaticBindingMap::value_type e(id, sb);
|
||||
if ((access == ReadAccess) || (access == ReadWriteAccess))
|
||||
regionalFrame->staticReadBindings.insert(e);
|
||||
if ((access == WriteAccess) || (access == ReadWriteAccess))
|
||||
regionalFrame->staticWriteBindings.insert(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
|
@ -720,10 +790,13 @@ namespace MetaData {
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
// clone a context
|
||||
Context::Context(Context *cxt) : strict(cxt->strict), openNamespaces(cxt->openNamespaces)
|
||||
{
|
||||
ASSERT(false); // ?? used ??
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* Multiname
|
||||
|
@ -742,7 +815,14 @@ namespace MetaData {
|
|||
|
||||
void Multiname::addNamespace(Context &cxt)
|
||||
{
|
||||
for (NamespaceListIterator nli = cxt.openNamespaces.begin(), end = cxt.openNamespaces.end();
|
||||
addNamespace(&cxt.openNamespaces);
|
||||
}
|
||||
|
||||
|
||||
// add every namespace from the list to this Multiname
|
||||
void Multiname::addNamespace(NamespaceList *ns)
|
||||
{
|
||||
for (NamespaceListIterator nli = ns->begin(), end = ns->end();
|
||||
(nli != end); nli++)
|
||||
nsList.push_back(*nli);
|
||||
}
|
||||
|
@ -1120,15 +1200,44 @@ namespace MetaData {
|
|||
reportError(kind, message, pos, str.c_str());
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* Pond
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
Pond::Pond(size_t sz, Pond *next) : pondSize(sz + POND_SIZE), pondBase(new uint8[pondSize]), pondTop(pondBase), nextPond(next)
|
||||
{
|
||||
}
|
||||
|
||||
void *Pond::allocFromPond(size_t sz)
|
||||
{
|
||||
if (sz > (pondSize - (pondTop - pondBase))) {
|
||||
if (nextPond == NULL)
|
||||
nextPond = new Pond(sz, nextPond);
|
||||
return nextPond->allocFromPond(sz);
|
||||
}
|
||||
void *p = pondTop;
|
||||
pondTop += sz;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* JS2Object
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
Pond JS2Object::pond(POND_SIZE, NULL);
|
||||
|
||||
void *JS2Object::operator new(size_t s)
|
||||
{
|
||||
return STD::malloc(s);
|
||||
// make sure that the thing is 8-byte aligned
|
||||
if (s & 0x7) s += 8 - (s & 0x7);
|
||||
|
||||
return pond.allocFromPond(s);
|
||||
|
||||
}
|
||||
|
||||
}; // namespace MetaData
|
||||
|
|
|
@ -64,7 +64,23 @@ enum ObjectKind {
|
|||
BlockKind,
|
||||
PrototypeInstanceKind,
|
||||
FixedInstanceKind,
|
||||
DynamicInstanceKind };
|
||||
DynamicInstanceKind,
|
||||
MultinameKind
|
||||
};
|
||||
|
||||
#define POND_SIZE (8000)
|
||||
|
||||
class Pond {
|
||||
public:
|
||||
Pond(size_t sz, Pond *nextPond);
|
||||
|
||||
void *allocFromPond(size_t t);
|
||||
|
||||
size_t pondSize;
|
||||
uint8 *pondBase;
|
||||
uint8 *pondTop;
|
||||
Pond *nextPond;
|
||||
};
|
||||
|
||||
class JS2Object {
|
||||
// Every object is either undefined, null, a Boolean,
|
||||
|
@ -76,7 +92,7 @@ public:
|
|||
|
||||
ObjectKind kind;
|
||||
|
||||
|
||||
static Pond pond;
|
||||
void *operator new(size_t s);
|
||||
|
||||
|
||||
|
@ -87,28 +103,31 @@ public:
|
|||
|
||||
class Attribute : public JS2Object {
|
||||
public:
|
||||
enum AttributeKind { TrueKind, FalseKind, NamespaceKind, CompoundKind } kind;
|
||||
enum AttributeKind { TrueAttr, FalseAttr, NamespaceAttr, CompoundAttr };
|
||||
enum MemberModifier { NoModifier, Static, Constructor, Operator, Abstract, Virtual, Final};
|
||||
enum OverrideModifier { NoOverride, DoOverride, DontOverride, OverrideUndefined };
|
||||
|
||||
|
||||
Attribute(AttributeKind kind) : JS2Object(AttributeObjectKind), kind(kind) { }
|
||||
Attribute(AttributeKind akind) : JS2Object(AttributeObjectKind), attrKind(akind) { }
|
||||
|
||||
static Attribute *combineAttributes(Attribute *a, Attribute *b);
|
||||
static CompoundAttribute *toCompoundAttribute(Attribute *a);
|
||||
|
||||
virtual CompoundAttribute *toCompoundAttribute() { ASSERT(false); return NULL; }
|
||||
|
||||
|
||||
AttributeKind attrKind;
|
||||
|
||||
};
|
||||
|
||||
// A Namespace (is also an attribute)
|
||||
class Namespace : public Attribute {
|
||||
public:
|
||||
Namespace(StringAtom &name) : Attribute(NamespaceKind), name(name) { }
|
||||
Namespace(const StringAtom &name) : Attribute(NamespaceAttr), name(name) { }
|
||||
|
||||
virtual CompoundAttribute *toCompoundAttribute();
|
||||
|
||||
StringAtom &name; // The namespace's name used by toString
|
||||
const StringAtom &name; // The namespace's name used by toString
|
||||
};
|
||||
|
||||
// A QualifiedName is the combination of an identifier and a namespace
|
||||
|
@ -128,12 +147,17 @@ public:
|
|||
// Pointers to Multiname instances get embedded in the bytecode.
|
||||
typedef std::vector<Namespace *> NamespaceList;
|
||||
typedef NamespaceList::iterator NamespaceListIterator;
|
||||
class Multiname {
|
||||
class Multiname : public JS2Object {
|
||||
public:
|
||||
|
||||
Multiname(const StringAtom &name) : name(name) { }
|
||||
Multiname(const StringAtom &name, Context &cxt) : name(name) { addNamespace(cxt); }
|
||||
Multiname(const StringAtom &name) : JS2Object(MultinameKind), name(name), qualified(false) { }
|
||||
Multiname(const StringAtom &name, bool qualified) : JS2Object(MultinameKind), name(name), qualified(qualified) { }
|
||||
|
||||
|
||||
void emitBytecode(BytecodeContainer *bCon) { bCon->emitOp(qualified ? eQMultiname : eMultiname); bCon->addMultiname(this); }
|
||||
|
||||
void addNamespace(Namespace *ns) { nsList.push_back(ns); }
|
||||
void addNamespace(NamespaceList *ns);
|
||||
void addNamespace(Context &cxt);
|
||||
|
||||
bool matches(QualifiedName &q) { return (name == q.id) && onList(q.nameSpace); }
|
||||
|
@ -141,6 +165,7 @@ public:
|
|||
|
||||
NamespaceList nsList;
|
||||
const StringAtom &name;
|
||||
bool qualified; // true for q::a, otherwise false
|
||||
|
||||
};
|
||||
|
||||
|
@ -184,6 +209,7 @@ public:
|
|||
class Variable : public StaticMember {
|
||||
public:
|
||||
Variable() : StaticMember(StaticMember::Variable), type(NULL), value(JS2VAL_VOID), immutable(false) { }
|
||||
Variable(JS2Class *type, js2val value, bool immutable) : StaticMember(StaticMember::Variable), type(type), value(value), immutable(immutable) { }
|
||||
|
||||
JS2Class *type; // Type of values that may be stored in this variable
|
||||
js2val value; // This variable's current value; future if the variable has not been declared yet;
|
||||
|
@ -401,8 +427,8 @@ class LexicalReference : public Reference {
|
|||
// q::a.
|
||||
public:
|
||||
LexicalReference(const StringAtom &name, bool strict) : variableMultiname(new Multiname(name)), env(NULL), strict(strict) { }
|
||||
LexicalReference(const StringAtom &name, const StringAtom &qualifiedName, bool strict) : variableMultiname(new Multiname(name)), env(NULL), strict(strict) { }
|
||||
LexicalReference(Multiname *vm, Environment *env, bool strict) : variableMultiname(vm), env(env), strict(strict) { }
|
||||
LexicalReference(const StringAtom &name, bool strict, bool qualified) : variableMultiname(new Multiname(name, qualified)), env(NULL), strict(strict) { }
|
||||
|
||||
|
||||
Multiname *variableMultiname; // A nonempty set of qualified names to which this reference can refer
|
||||
Environment *env; // The environment in which the reference was created.
|
||||
|
@ -410,8 +436,8 @@ public:
|
|||
|
||||
|
||||
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalRead); bCon->addMultiname(variableMultiname); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalWrite); bCon->addMultiname(variableMultiname); }
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); bCon->emitOp(eLexicalRead); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); bCon->emitOp(eLexicalWrite); }
|
||||
};
|
||||
|
||||
class DotReference : public Reference {
|
||||
|
@ -511,6 +537,7 @@ public:
|
|||
js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase);
|
||||
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase);
|
||||
|
||||
void defineStaticMember(JS2Metadata *meta, const StringAtom &id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m);
|
||||
|
||||
private:
|
||||
Frame *firstFrame;
|
||||
|
@ -532,14 +559,14 @@ public:
|
|||
// The 'true' attribute
|
||||
class TrueAttribute : public Attribute {
|
||||
public:
|
||||
TrueAttribute() : Attribute(TrueKind) { }
|
||||
TrueAttribute() : Attribute(TrueAttr) { }
|
||||
virtual CompoundAttribute *toCompoundAttribute();
|
||||
};
|
||||
|
||||
// The 'false' attribute
|
||||
class FalseAttribute : public Attribute {
|
||||
public:
|
||||
FalseAttribute() : Attribute(FalseKind) { }
|
||||
FalseAttribute() : Attribute(FalseAttr) { }
|
||||
};
|
||||
|
||||
// Compound attribute objects are all values obtained from combining zero or more syntactic attributes
|
||||
|
@ -624,6 +651,7 @@ public:
|
|||
JS2Class *characterClass;
|
||||
JS2Class *stringClass;
|
||||
JS2Class *objectClass;
|
||||
JS2Class *namespaceClass;
|
||||
|
||||
Parser *mParser; // used for error reporting
|
||||
size_t errorPos;
|
||||
|
|
|
@ -35,27 +35,38 @@
|
|||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
push(OBJECT_TO_JS2VAL(mn));
|
||||
}
|
||||
break;
|
||||
|
||||
case eQualifiedMultiname: {
|
||||
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(meta->cxt);
|
||||
mn->addNamespace(checked_cast<Namespace *>(obj));
|
||||
push(OBJECT_TO_JS2VAL(mn));
|
||||
}
|
||||
break;
|
||||
|
||||
case eLexicalRead: {
|
||||
js2val n = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(n));
|
||||
meta->env.lexicalRead(meta, mn, phase);
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
push(meta->env.lexicalRead(meta, mn, phase));
|
||||
}
|
||||
break;
|
||||
|
||||
case eLexicalWrite: {
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
retval = pop();
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче