зеркало из https://github.com/mozilla/pjs.git
WriteProperty work-in-progress (broken!)
This commit is contained in:
Родитель
ea786ffe5d
Коммит
4f0cf5d56e
|
@ -54,7 +54,8 @@ static const char *const kindStrings[] = {
|
|||
"User exception", // 'throw' from user code
|
||||
"Definition error", // a monkey is a small cup of milk
|
||||
"Bad Value error", // bad value, no biscuit
|
||||
"Compile Expression error" // invalid compile-time execution
|
||||
"Compile expression error", // invalid compile-time execution
|
||||
"Uninitialized error" // read before write
|
||||
};
|
||||
|
||||
// Return a null-terminated string describing the exception's kind.
|
||||
|
|
|
@ -60,7 +60,8 @@ namespace JavaScript
|
|||
definitionError,
|
||||
badValueError,
|
||||
compileExpressionError,
|
||||
propertyAccessError
|
||||
propertyAccessError,
|
||||
uninitializedError
|
||||
};
|
||||
|
||||
Kind kind; // The exception's kind
|
||||
|
|
|
@ -108,6 +108,9 @@ public:
|
|||
float64 toNumber(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else if (JS2VAL_IS_DOUBLE(x)) return *JS2VAL_TO_DOUBLE(x); else return convertValueToDouble(x); }
|
||||
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
|
||||
|
||||
|
||||
js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please
|
||||
|
||||
uint8 *pc;
|
||||
BytecodeContainer *bCon;
|
||||
JS2Metadata *meta;
|
||||
|
|
|
@ -159,30 +159,17 @@ namespace MetaData {
|
|||
// the type and the value are 'future'
|
||||
}
|
||||
break;
|
||||
case Attribute::Abstract:
|
||||
case Attribute::Virtual:
|
||||
case Attribute::Final:
|
||||
{
|
||||
JS2Class *c = checked_cast<JS2Class *>(env->getTopFrame());
|
||||
InstanceMember *m = NULL;
|
||||
switch (memberMod) {
|
||||
case Attribute::Abstract:
|
||||
if (v->initializer)
|
||||
reportError(Exception::syntaxError, "Abstract member may not have initializer", p->pos);
|
||||
m = new InstanceAccessor(NULL, false);
|
||||
break;
|
||||
case Attribute::Virtual:
|
||||
m = new InstanceVariable(immutable, false);
|
||||
c->slotCount++;
|
||||
break;
|
||||
case Attribute::Final:
|
||||
m = new InstanceVariable(immutable, true);
|
||||
c->slotCount++;
|
||||
break;
|
||||
}
|
||||
InstanceMember *m = new InstanceVariable(immutable, (memberMod == Attribute::Final), c->slotCount++);
|
||||
defineInstanceMember(c, cxt, *name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, m, p->pos);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
reportError(Exception::definitionError, "Illegal attribute", p->pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1219,13 +1206,13 @@ doBinary:
|
|||
else
|
||||
writeStatus = new OverrideStatus(NULL, id);
|
||||
|
||||
if ((!readStatus->overriddenMember && (readStatus->overriddenMember != PotentialConflict))
|
||||
|| (!writeStatus->overriddenMember && (writeStatus->overriddenMember != PotentialConflict))) {
|
||||
if ((readStatus->overriddenMember && (readStatus->overriddenMember != PotentialConflict))
|
||||
|| (writeStatus->overriddenMember && (writeStatus->overriddenMember != PotentialConflict))) {
|
||||
if ((overrideMod != Attribute::DoOverride) && (overrideMod != Attribute::OverrideUndefined))
|
||||
reportError(Exception::definitionError, "Illegal override", pos);
|
||||
}
|
||||
else {
|
||||
if ((readStatus->overriddenMember = PotentialConflict) || (writeStatus->overriddenMember == PotentialConflict)) {
|
||||
if ((readStatus->overriddenMember == PotentialConflict) || (writeStatus->overriddenMember == PotentialConflict)) {
|
||||
if ((overrideMod != Attribute::DontOverride) && (overrideMod != Attribute::OverrideUndefined))
|
||||
reportError(Exception::definitionError, "Illegal override", pos);
|
||||
}
|
||||
|
@ -1411,7 +1398,7 @@ doBinary:
|
|||
return false; // 'None'
|
||||
}
|
||||
|
||||
bool JS2Metadata::writeDynamicProperty(Frame *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase)
|
||||
bool JS2Metadata::writeDynamicProperty(JS2Object *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase)
|
||||
{
|
||||
ASSERT(container && ((container->kind == DynamicInstanceKind)
|
||||
|| (container->kind == GlobalObjectKind)
|
||||
|
@ -1533,14 +1520,8 @@ readClassProperty:
|
|||
case PackageKind:
|
||||
case FunctionKind:
|
||||
case BlockKind:
|
||||
{
|
||||
StaticMember *m = findFlatMember(checked_cast<Frame *>(container), multiname, ReadAccess, phase);
|
||||
if (!m && (container->kind == GlobalObjectKind))
|
||||
return readDynamicProperty(container, multiname, lookupKind, phase, rval);
|
||||
else
|
||||
return readStaticMember(m, phase, rval);
|
||||
}
|
||||
break;
|
||||
return readProperty(checked_cast<Frame *>(container), multiname, lookupKind, ReadAccess, phase);
|
||||
|
||||
case ClassKind:
|
||||
{
|
||||
MemberDescriptor m2;
|
||||
|
@ -1559,6 +1540,7 @@ readClassProperty:
|
|||
|
||||
case PrototypeInstanceKind:
|
||||
return readDynamicProperty(container, multiname, lookupKind, phase, rval);
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
return false;
|
||||
|
@ -1571,22 +1553,10 @@ readClassProperty:
|
|||
&& ((JS2VAL_TO_OBJECT(thisObjVal)->kind == DynamicInstanceKind)
|
||||
|| (JS2VAL_TO_OBJECT(thisObjVal)->kind == FixedInstanceKind)));
|
||||
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisObjVal);
|
||||
Slot *s;
|
||||
uint32 slotCount;
|
||||
if (thisObj->kind == DynamicInstanceKind) {
|
||||
s = checked_cast<DynamicInstance *>(thisObj)->slots;
|
||||
slotCount = checked_cast<DynamicInstance *>(thisObj)->type->slotCount;
|
||||
}
|
||||
else {
|
||||
s = checked_cast<FixedInstance *>(thisObj)->slots;
|
||||
slotCount = checked_cast<FixedInstance *>(thisObj)->type->slotCount;
|
||||
}
|
||||
for (uint32 i = 0; i < slotCount; i++) {
|
||||
if (s[i].id == id)
|
||||
return &s[i];
|
||||
}
|
||||
ASSERT(false);
|
||||
return NULL;
|
||||
if (thisObj->kind == DynamicInstanceKind)
|
||||
return &checked_cast<DynamicInstance *>(thisObj)->slots[id->slotIndex];
|
||||
else
|
||||
return &checked_cast<FixedInstance *>(thisObj)->slots[id->slotIndex];
|
||||
}
|
||||
|
||||
|
||||
|
@ -1601,7 +1571,8 @@ readClassProperty:
|
|||
if ((phase == CompilePhase) && !mv->immutable)
|
||||
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
|
||||
Slot *s = findSlot(containerVal, mv);
|
||||
|
||||
if (JS2VAL_IS_UNINITIALIZED(s->value))
|
||||
reportError(Exception::uninitializedError, "Reference to uninitialized instance variable", engine->errorPos());
|
||||
*rval = s->value;
|
||||
return true;
|
||||
}
|
||||
|
@ -1626,6 +1597,75 @@ readClassProperty:
|
|||
return readStaticMember(m, phase, rval);
|
||||
}
|
||||
|
||||
// Write the value of a property in the container. Return true/false if that container has
|
||||
// the property or not.
|
||||
bool JS2Metadata::writeProperty(js2val containerVal, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase)
|
||||
{
|
||||
if (JS2VAL_IS_PRIMITIVE(containerVal))
|
||||
return false;
|
||||
JS2Object *container = JS2VAL_TO_OBJECT(containerVal);
|
||||
switch (container->kind) {
|
||||
case AttributeObjectKind:
|
||||
case MultinameKind:
|
||||
return false;
|
||||
|
||||
case FixedInstanceKind:
|
||||
case DynamicInstanceKind:
|
||||
{
|
||||
InstanceBinding *ib = resolveInstanceMemberName(objectType(containerVal), multiname, WriteAccess, phase);
|
||||
if ((ib == NULL) && (container->kind == DynamicInstanceKind))
|
||||
return writeDynamicProperty(container, multiname, createIfMissing, newValue, phase);
|
||||
else
|
||||
return writeInstanceMember();
|
||||
}
|
||||
|
||||
case SystemKind:
|
||||
case GlobalObjectKind:
|
||||
case PackageKind:
|
||||
case FunctionKind:
|
||||
case BlockKind:
|
||||
return writeProperty(checked_cast<Frame *>(container), multiname, lookupKind, createIfMissing, newValue, phase);
|
||||
|
||||
case ClassKind:
|
||||
break;
|
||||
|
||||
case PrototypeInstanceKind:
|
||||
return writeDynamicProperty(container, multiname, createIfMissing, newValue, phase);
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool JS2Metadata::writeInstanceMember(JS2Object *thisObj, JS2Class *c, QualifiedName *qname, js2val newValue, Phase phase)
|
||||
{
|
||||
if (phase == CompilePhase)
|
||||
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
|
||||
InstanceMember *m = findInstanceMember(c, qname, WriteAccess);
|
||||
if (m == NULL) return false;
|
||||
switch (m->kind) {
|
||||
case InstanceMember::InstanceVariableKind:
|
||||
{
|
||||
InstanceVariable *mv = checked_cast<InstanceVariable *>(m);
|
||||
Slot *s = findSlot(containerVal, mv);
|
||||
if (mv->immutable && JS2VAL_IS_INITIALIZED(s->value))
|
||||
reportError(Exception::propertyAccessError, "Reinitialization of constant", engine->errorPos());
|
||||
s->value = engine->assignmentConversion(newValue, mv->type);
|
||||
return true;
|
||||
}
|
||||
|
||||
case InstanceMember::InstanceMethodKind:
|
||||
case InstanceMember::InstanceAccessorKind:
|
||||
reportError(Exception::propertyAccessError, "Attempt to write to a method", engine->errorPos());
|
||||
break;
|
||||
}
|
||||
ASSERT(false);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Write the value of a property in the frame. Return true/false if that frame has
|
||||
// the property or not.
|
||||
bool JS2Metadata::writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase)
|
||||
|
|
|
@ -134,7 +134,7 @@ public:
|
|||
class Attribute : public JS2Object {
|
||||
public:
|
||||
enum AttributeKind { TrueAttr, FalseAttr, NamespaceAttr, CompoundAttr };
|
||||
enum MemberModifier { NoModifier, Static, Constructor, Operator, Abstract, Virtual, Final};
|
||||
enum MemberModifier { NoModifier, Static, Constructor, Abstract, Virtual, Final};
|
||||
enum OverrideModifier { NoOverride, DoOverride, DontOverride, OverrideUndefined };
|
||||
|
||||
|
||||
|
@ -308,10 +308,11 @@ public:
|
|||
|
||||
class InstanceVariable : public InstanceMember {
|
||||
public:
|
||||
InstanceVariable(bool immutable, bool final) : InstanceMember(InstanceVariableKind, final), immutable(immutable) { }
|
||||
InstanceVariable(bool immutable, bool final, uint32 slotIndex) : InstanceMember(InstanceVariableKind, final), immutable(immutable), slotIndex(slotIndex) { }
|
||||
JS2Class *type; // Type of values that may be stored in this variable
|
||||
Invokable *evalInitialValue; // A function that computes this variable's initial value
|
||||
bool immutable; // true if this variable's value may not be changed once set
|
||||
uint32 slotIndex; // The index into an instance's slot array in which this variable is stored
|
||||
};
|
||||
|
||||
class InstanceMethod : public InstanceMember {
|
||||
|
@ -418,7 +419,8 @@ public:
|
|||
// A SLOT record describes the value of one fixed property of one instance.
|
||||
class Slot {
|
||||
public:
|
||||
InstanceVariable *id; // The instance variable whose value this slot carries
|
||||
// We keep the slotIndex in the InstanceVariable rather than go looking for a specific id
|
||||
// InstanceVariable *id; // The instance variable whose value this slot carries
|
||||
js2val value; // This fixed property's current value; uninitialised if the fixed property is an uninitialised constant
|
||||
};
|
||||
|
||||
|
@ -509,8 +511,8 @@ public:
|
|||
Multiname *propertyMultiname; // A nonempty set of qualified names to which this reference can refer (b
|
||||
// qualified with the namespace q or all currently open namespaces in the
|
||||
// example above)
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotRead, pos); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotWrite, pos); }
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotRead, pos); bCon->addMultiname(propertyMultiname); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotWrite, pos); bCon->addMultiname(propertyMultiname); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -699,8 +701,9 @@ public:
|
|||
bool readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval);
|
||||
|
||||
|
||||
bool writeProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase);
|
||||
bool writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase);
|
||||
bool writeDynamicProperty(Frame *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase);
|
||||
bool writeDynamicProperty(JS2Object *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase);
|
||||
bool writeStaticMember(StaticMember *m, js2val newValue, Phase phase);
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
// Read a multiname property from a base object, push the value onto the stack
|
||||
case eDotRead:
|
||||
{
|
||||
LookupKind lookup(false, NULL);
|
||||
|
@ -42,7 +43,22 @@
|
|||
}
|
||||
break;
|
||||
|
||||
// Pop a multiname object and read it's value from the environment on to the stack.
|
||||
// Write the top value to a multiname property in a base object, leave
|
||||
// the value on the stack top
|
||||
case eDotWrite:
|
||||
{
|
||||
retval = pop();
|
||||
LookupKind lookup(false, NULL);
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
js2val baseVal = pop();
|
||||
if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &retval))
|
||||
meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
// Read the multiname from the current environment, push it's value on the stack
|
||||
case eLexicalRead:
|
||||
{
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
|
@ -52,14 +68,14 @@
|
|||
}
|
||||
break;
|
||||
|
||||
// Pop a value and a multiname. Write the value to the multiname in the environment, leave
|
||||
// Write the top value to the multiname in the environment, leave
|
||||
// the value on the stack top.
|
||||
case eLexicalWrite:
|
||||
{
|
||||
retval = top();
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#define JS2VAL_UNINITIALIZED 0x80 /* reserve this object reference value as an indication
|
||||
that a variable has yet to be initialized */
|
||||
#define JS2VAL_IS_INITIALIZED(v) (v != JS2VAL_UNINITIALIZED)
|
||||
#define JS2VAL_IS_UNINITIALIZED(v) (v == JS2VAL_UNINITIALIZED)
|
||||
|
||||
/* Type tag bitfield length and derived macros. */
|
||||
#define JS2VAL_TAGBITS 3
|
||||
|
|
Загрузка…
Ссылка в новой задаче