Rework properties
This brings the basic structure or accessing properties more in line with the EcmaScript 5.1 specification. There's however still quite some work to be done to make things fully compliant. Change-Id: If55afd7ae6e4f7aa5ce06afe49b1453b537ac98b Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
parent
6ace5d1a2b
commit
aa96410f3f
|
@ -69,55 +69,86 @@ void Object::setProperty(Context *ctx, const QString &name, void (*code)(Context
|
|||
setProperty(ctx, name, Value::fromObject(ctx->engine->newNativeFunction(ctx, code)));
|
||||
}
|
||||
|
||||
Value Object::getProperty(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
Value Object::getProperty(Context *ctx, String *name)
|
||||
{
|
||||
if (name->isEqualTo(ctx->engine->id___proto__))
|
||||
return Value::fromObject(prototype);
|
||||
else if (Value *v = getPropertyDescriptor(ctx, name, attributes))
|
||||
return *v;
|
||||
|
||||
PropertyDescriptor tmp;
|
||||
if (PropertyDescriptor *p = getPropertyDescriptor(ctx, name, &tmp)) {
|
||||
if (p->isData())
|
||||
return p->value;
|
||||
if (!p->get)
|
||||
return Value::undefinedValue();
|
||||
FunctionObject *f = p->get->asFunctionObject();
|
||||
if (f) {
|
||||
f->call(ctx);
|
||||
return ctx->result;
|
||||
}
|
||||
}
|
||||
return Value::undefinedValue();
|
||||
}
|
||||
|
||||
Value *Object::getOwnProperty(Context *, String *name, PropertyAttributes *attributes)
|
||||
// Section 8.12.1
|
||||
PropertyDescriptor *Object::getOwnProperty(Context *, String *name)
|
||||
{
|
||||
if (members) {
|
||||
if (Property *prop = members->find(name)) {
|
||||
if (attributes)
|
||||
*attributes = prop->attributes;
|
||||
return &prop->value;
|
||||
}
|
||||
if (members)
|
||||
return members->find(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PropertyDescriptor *Object::getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill)
|
||||
{
|
||||
if (PropertyDescriptor *p = getOwnProperty(ctx, name))
|
||||
return p;
|
||||
|
||||
if (prototype)
|
||||
return prototype->getPropertyDescriptor(ctx, name, to_fill);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Section 8.12.5
|
||||
void Object::setProperty(Context *ctx, String *name, const Value &value, bool throwException)
|
||||
{
|
||||
if (!canSetProperty(ctx, name)) {
|
||||
if (throwException)
|
||||
__qmljs_throw_type_error(ctx);
|
||||
return;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Value *Object::getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
{
|
||||
if (Value *prop = getOwnProperty(ctx, name, attributes))
|
||||
return prop;
|
||||
else if (prototype)
|
||||
return prototype->getPropertyDescriptor(ctx, name, attributes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Object::setProperty(Context *, String *name, const Value &value, bool flag)
|
||||
{
|
||||
Q_UNUSED(flag);
|
||||
|
||||
if (! members)
|
||||
members = new Table();
|
||||
members = new PropertyTable();
|
||||
|
||||
members->insert(name, value);
|
||||
PropertyDescriptor *pd = getOwnProperty(ctx, name);
|
||||
if (pd) {
|
||||
if (pd->isData()) {
|
||||
pd->value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
PropertyDescriptor *p = members->insert(name);
|
||||
*p = PropertyDescriptor::fromValue(value);
|
||||
}
|
||||
|
||||
// Section 8.12.4
|
||||
bool Object::canSetProperty(Context *ctx, String *name)
|
||||
{
|
||||
PropertyAttributes attrs = PropertyAttributes();
|
||||
if (getOwnProperty(ctx, name, &attrs)) {
|
||||
return attrs & WritableAttribute;
|
||||
} else if (! prototype) {
|
||||
if (PropertyDescriptor *p = getOwnProperty(ctx, name)) {
|
||||
if (p->isAccessor())
|
||||
return p->get != 0;
|
||||
return p->isWritable();
|
||||
}
|
||||
|
||||
if (! prototype)
|
||||
return extensible;
|
||||
} else if (prototype->getPropertyDescriptor(ctx, name, &attrs)) {
|
||||
return attrs & WritableAttribute;
|
||||
|
||||
PropertyDescriptor tmp;
|
||||
if (PropertyDescriptor *p = prototype->getPropertyDescriptor(ctx, name, &tmp)) {
|
||||
if (p->isAccessor())
|
||||
return p->get != 0;
|
||||
if (!extensible)
|
||||
return false;
|
||||
return p->isWritable();
|
||||
} else {
|
||||
return extensible;
|
||||
}
|
||||
|
@ -142,17 +173,26 @@ bool Object::deleteProperty(Context *, String *name, bool flag)
|
|||
return false;
|
||||
}
|
||||
|
||||
void Object::defineOwnProperty(Context *ctx, const Value &getter, const Value &setter, bool flag)
|
||||
bool Object::defineOwnProperty(Context *ctx, String *name, const Value &getter, const Value &setter, bool flag)
|
||||
{
|
||||
Q_UNUSED(getter);
|
||||
Q_UNUSED(setter);
|
||||
Q_UNUSED(flag);
|
||||
ctx->throwUnimplemented(QStringLiteral("defineOwnProperty"));
|
||||
if (!members)
|
||||
members = new PropertyTable();
|
||||
|
||||
PropertyDescriptor *p = getOwnProperty(ctx, name);
|
||||
if (!p) {
|
||||
if (!extensible)
|
||||
goto reject;
|
||||
}
|
||||
|
||||
reject:
|
||||
if (flag)
|
||||
__qmljs_throw_type_error(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
String *ForEachIteratorObject::nextPropertyName()
|
||||
{
|
||||
Property *p = 0;
|
||||
PropertyTableEntry *p = 0;
|
||||
while (1) {
|
||||
if (!current)
|
||||
return 0;
|
||||
|
@ -171,11 +211,11 @@ String *ForEachIteratorObject::nextPropertyName()
|
|||
}
|
||||
}
|
||||
|
||||
Value ArrayObject::getProperty(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
Value ArrayObject::getProperty(Context *ctx, String *name)
|
||||
{
|
||||
if (name->isEqualTo(ctx->engine->id_length))
|
||||
return Value::fromDouble(value.size());
|
||||
return Object::getProperty(ctx, name, attributes);
|
||||
return Object::getProperty(ctx, name);
|
||||
}
|
||||
|
||||
bool FunctionObject::hasInstance(Context *ctx, const Value &value)
|
||||
|
@ -250,7 +290,7 @@ void ScriptFunction::call(VM::Context *ctx)
|
|||
function->code(ctx, function->codeData);
|
||||
}
|
||||
|
||||
Value RegExpObject::getProperty(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
Value RegExpObject::getProperty(Context *ctx, String *name)
|
||||
{
|
||||
QString n = name->toQString();
|
||||
if (n == QLatin1String("source"))
|
||||
|
@ -263,7 +303,7 @@ Value RegExpObject::getProperty(Context *ctx, String *name, PropertyAttributes *
|
|||
return Value::fromBoolean(value.patternOptions() & QRegularExpression::MultilineOption);
|
||||
else if (n == QLatin1String("lastIndex"))
|
||||
return lastIndex;
|
||||
return Object::getProperty(ctx, name, attributes);
|
||||
return Object::getProperty(ctx, name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -277,23 +317,23 @@ void ScriptFunction::construct(VM::Context *ctx)
|
|||
function->code(ctx, function->codeData);
|
||||
}
|
||||
|
||||
Value *ActivationObject::getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
PropertyDescriptor *ActivationObject::getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill)
|
||||
{
|
||||
if (context) {
|
||||
for (unsigned int i = 0; i < context->varCount; ++i) {
|
||||
String *var = context->vars[i];
|
||||
if (__qmljs_string_equal(context, var, name)) {
|
||||
if (attributes)
|
||||
*attributes = PropertyAttributes(*attributes | WritableAttribute);
|
||||
return &context->locals[i];
|
||||
*to_fill = PropertyDescriptor::fromValue(context->locals[i]);
|
||||
to_fill->writable = PropertyDescriptor::Set;
|
||||
return to_fill;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < context->formalCount; ++i) {
|
||||
String *formal = context->formals[i];
|
||||
if (__qmljs_string_equal(context, formal, name)) {
|
||||
if (attributes)
|
||||
*attributes = PropertyAttributes(*attributes | WritableAttribute);
|
||||
return &context->arguments[i];
|
||||
*to_fill = PropertyDescriptor::fromValue(context->arguments[i]);
|
||||
to_fill->writable = PropertyDescriptor::Set;
|
||||
return to_fill;
|
||||
}
|
||||
}
|
||||
if (name->isEqualTo(ctx->engine->id_arguments)) {
|
||||
|
@ -302,29 +342,32 @@ Value *ActivationObject::getPropertyDescriptor(Context *ctx, String *name, Prope
|
|||
arguments.objectValue()->prototype = ctx->engine->objectPrototype;
|
||||
}
|
||||
|
||||
return &arguments;
|
||||
*to_fill = PropertyDescriptor::fromValue(arguments);
|
||||
return to_fill;
|
||||
}
|
||||
}
|
||||
if (Value *prop = Object::getPropertyDescriptor(ctx, name, attributes))
|
||||
return prop;
|
||||
return 0;
|
||||
|
||||
return Object::getPropertyDescriptor(ctx, name, to_fill);
|
||||
}
|
||||
|
||||
Value ArgumentsObject::getProperty(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
Value ArgumentsObject::getProperty(Context *ctx, String *name)
|
||||
{
|
||||
if (name->isEqualTo(ctx->engine->id_length))
|
||||
return Value::fromDouble(context->argumentCount);
|
||||
return Object::getProperty(ctx, name, attributes);
|
||||
return Object::getProperty(ctx, name);
|
||||
}
|
||||
|
||||
Value *ArgumentsObject::getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
PropertyDescriptor *ArgumentsObject::getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill)
|
||||
{
|
||||
if (context) {
|
||||
const quint32 i = Value::fromString(name).toUInt32(ctx);
|
||||
if (i < context->argumentCount)
|
||||
return &context->arguments[i];
|
||||
if (i < context->argumentCount) {
|
||||
*to_fill = PropertyDescriptor::fromValue(context->arguments[i]);
|
||||
return to_fill;
|
||||
}
|
||||
}
|
||||
return Object::getPropertyDescriptor(ctx, name, attributes);
|
||||
|
||||
return Object::getPropertyDescriptor(ctx, name, to_fill);
|
||||
}
|
||||
|
||||
ExecutionEngine::ExecutionEngine()
|
||||
|
|
164
qmljs_objects.h
164
qmljs_objects.h
|
@ -111,39 +111,80 @@ private:
|
|||
mutable unsigned _hashValue;
|
||||
};
|
||||
|
||||
struct Property {
|
||||
String *name;
|
||||
Value value;
|
||||
PropertyAttributes attributes;
|
||||
Property *next;
|
||||
int index;
|
||||
struct PropertyDescriptor {
|
||||
enum Type {
|
||||
Generic,
|
||||
Data,
|
||||
Accessor
|
||||
};
|
||||
enum State {
|
||||
Undefined,
|
||||
Unset,
|
||||
Set
|
||||
};
|
||||
union {
|
||||
Value value;
|
||||
struct {
|
||||
Object *get;
|
||||
Object *set;
|
||||
};
|
||||
};
|
||||
uint type : 8;
|
||||
uint writable : 8;
|
||||
uint enumberable : 8;
|
||||
uint configurable : 8;
|
||||
|
||||
inline Property(String *name, const Value &value, PropertyAttributes flags = NoAttributes)
|
||||
{ init(name, value, flags); }
|
||||
|
||||
inline void init(String *name, const Value &value, PropertyAttributes flags = NoAttributes)
|
||||
{
|
||||
this->name = name;
|
||||
this->value = value;
|
||||
this->attributes = flags;
|
||||
this->next = 0;
|
||||
this->index = -1;
|
||||
static inline PropertyDescriptor fromValue(Value v) {
|
||||
PropertyDescriptor pd;
|
||||
pd.value = v;
|
||||
pd.type = Data;
|
||||
pd.writable = Set;
|
||||
pd.enumberable = Set;
|
||||
pd.configurable = Set;
|
||||
return pd;
|
||||
}
|
||||
static inline PropertyDescriptor fromAccessor(Object *getter, Object *setter) {
|
||||
PropertyDescriptor pd;
|
||||
pd.get = getter;
|
||||
pd.set = setter;
|
||||
pd.type = Accessor;
|
||||
pd.writable = Undefined;
|
||||
pd.enumberable = Set;
|
||||
pd.configurable = Set;
|
||||
return pd;
|
||||
}
|
||||
|
||||
inline bool isWritable() const { return attributes & WritableAttribute; }
|
||||
inline bool isEnumerable() const { return attributes & EnumerableAttribute; }
|
||||
inline bool isConfigurable() const { return attributes & ConfigurableAttribute; }
|
||||
inline bool isData() const { return type == Data; }
|
||||
inline bool isAccessor() const { return type == Accessor; }
|
||||
inline bool isGeneric() const { return type == Generic; }
|
||||
|
||||
inline bool isWritable() const { return writable == Set; }
|
||||
inline bool isEnumerable() const { return enumberable == Set; }
|
||||
inline bool isConfigurable() const { return configurable == Set; }
|
||||
};
|
||||
|
||||
struct PropertyTableEntry {
|
||||
PropertyDescriptor descriptor;
|
||||
String *name;
|
||||
PropertyTableEntry *next;
|
||||
int index;
|
||||
|
||||
inline PropertyTableEntry(String *name)
|
||||
: name(name),
|
||||
next(0),
|
||||
index(-1)
|
||||
{ }
|
||||
|
||||
inline bool hasName(String *n) const { return name->isEqualTo(n); }
|
||||
inline unsigned hashValue() const { return name->hashValue(); }
|
||||
};
|
||||
|
||||
class Table
|
||||
class PropertyTable
|
||||
{
|
||||
Q_DISABLE_COPY(Table)
|
||||
Q_DISABLE_COPY(PropertyTable)
|
||||
|
||||
public:
|
||||
Table()
|
||||
PropertyTable()
|
||||
: _properties(0)
|
||||
, _buckets(0)
|
||||
, _freeList(0)
|
||||
|
@ -151,7 +192,7 @@ public:
|
|||
, _bucketCount(0)
|
||||
, _allocated(0) {}
|
||||
|
||||
~Table()
|
||||
~PropertyTable()
|
||||
{
|
||||
qDeleteAll(_properties, _properties + _propertyCount + 1);
|
||||
delete[] _properties;
|
||||
|
@ -160,20 +201,20 @@ public:
|
|||
|
||||
inline bool isEmpty() const { return _propertyCount == -1; }
|
||||
|
||||
typedef Property **iterator;
|
||||
typedef PropertyTableEntry **iterator;
|
||||
inline iterator begin() const { return _properties; }
|
||||
inline iterator end() const { return _properties + (_propertyCount + 1); }
|
||||
|
||||
bool remove(String *name)
|
||||
{
|
||||
if (Property *prop = find(name)) {
|
||||
if (PropertyTableEntry *prop = findEntry(name)) {
|
||||
// ### TODO check if the property can be removed
|
||||
|
||||
Property *bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
PropertyTableEntry *bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
if (bucket == prop) {
|
||||
bucket = bucket->next;
|
||||
} else {
|
||||
for (Property *it = bucket; it; it = it->next) {
|
||||
for (PropertyTableEntry *it = bucket; it; it = it->next) {
|
||||
if (it->next == prop) {
|
||||
it->next = it->next->next;
|
||||
break;
|
||||
|
@ -189,10 +230,10 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
Property *find(String *name) const
|
||||
PropertyTableEntry *findEntry(String *name) const
|
||||
{
|
||||
if (_properties) {
|
||||
for (Property *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
|
||||
for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
|
||||
if (prop && (prop->name == name || prop->hasName(name)))
|
||||
return prop;
|
||||
}
|
||||
|
@ -201,32 +242,41 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
Property *insert(String *name, const Value &value)
|
||||
PropertyDescriptor *find(String *name) const
|
||||
{
|
||||
if (Property *prop = find(name)) {
|
||||
prop->value = value;
|
||||
return prop;
|
||||
if (_properties) {
|
||||
for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
|
||||
if (prop && (prop->name == name || prop->hasName(name)))
|
||||
return &prop->descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PropertyDescriptor *insert(String *name)
|
||||
{
|
||||
if (PropertyTableEntry *prop = findEntry(name))
|
||||
return &prop->descriptor;
|
||||
|
||||
if (++_propertyCount == _allocated) {
|
||||
if (! _allocated)
|
||||
_allocated = 4;
|
||||
else
|
||||
_allocated *= 2;
|
||||
|
||||
Property **properties = new Property*[_allocated];
|
||||
PropertyTableEntry **properties = new PropertyTableEntry*[_allocated];
|
||||
std::copy(_properties, _properties + _propertyCount, properties);
|
||||
delete[] _properties;
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
Property *prop;
|
||||
PropertyTableEntry *prop;
|
||||
if (_freeList) {
|
||||
prop = _freeList;
|
||||
_freeList = _freeList->next;
|
||||
prop->init(name, value);
|
||||
} else {
|
||||
prop = new Property(name, value);
|
||||
prop = new PropertyTableEntry(name);
|
||||
}
|
||||
|
||||
prop->index = _propertyCount;
|
||||
|
@ -235,12 +285,12 @@ public:
|
|||
if (! _buckets || 3 * _propertyCount >= 2 * _bucketCount) {
|
||||
rehash();
|
||||
} else {
|
||||
Property *&bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
PropertyTableEntry *&bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
prop->next = bucket;
|
||||
bucket = prop;
|
||||
}
|
||||
|
||||
return prop;
|
||||
return &prop->descriptor;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -252,12 +302,12 @@ private:
|
|||
_bucketCount = 11;
|
||||
|
||||
delete[] _buckets;
|
||||
_buckets = new Property *[_bucketCount];
|
||||
std::fill(_buckets, _buckets + _bucketCount, (Property *) 0);
|
||||
_buckets = new PropertyTableEntry *[_bucketCount];
|
||||
std::fill(_buckets, _buckets + _bucketCount, (PropertyTableEntry *) 0);
|
||||
|
||||
for (int i = 0; i <= _propertyCount; ++i) {
|
||||
Property *prop = _properties[i];
|
||||
Property *&bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
PropertyTableEntry *prop = _properties[i];
|
||||
PropertyTableEntry *&bucket = _buckets[prop->hashValue() % _bucketCount];
|
||||
prop->next = bucket;
|
||||
bucket = prop;
|
||||
}
|
||||
|
@ -265,9 +315,9 @@ private:
|
|||
|
||||
private:
|
||||
friend struct ForEachIteratorObject;
|
||||
Property **_properties;
|
||||
Property **_buckets;
|
||||
Property *_freeList;
|
||||
PropertyTableEntry **_properties;
|
||||
PropertyTableEntry **_buckets;
|
||||
PropertyTableEntry *_freeList;
|
||||
int _propertyCount;
|
||||
int _bucketCount;
|
||||
int _allocated;
|
||||
|
@ -276,7 +326,7 @@ private:
|
|||
struct Object {
|
||||
Object *prototype;
|
||||
String *klass;
|
||||
Table *members;
|
||||
PropertyTable *members;
|
||||
bool extensible;
|
||||
|
||||
Object()
|
||||
|
@ -299,14 +349,14 @@ struct Object {
|
|||
virtual ActivationObject *asActivationObject() { return 0; }
|
||||
virtual ArgumentsObject *asArgumentsObject() { return 0; }
|
||||
|
||||
virtual Value getProperty(Context *ctx, String *name, PropertyAttributes *attributes = 0);
|
||||
virtual Value *getOwnProperty(Context *ctx, String *name, PropertyAttributes *attributes = 0);
|
||||
virtual Value *getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes = 0);
|
||||
virtual void setProperty(Context *ctx, String *name, const Value &value, bool flag = false);
|
||||
virtual Value getProperty(Context *ctx, String *name);
|
||||
virtual PropertyDescriptor *getOwnProperty(Context *ctx, String *name);
|
||||
virtual PropertyDescriptor *getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill);
|
||||
virtual void setProperty(Context *ctx, String *name, const Value &value, bool throwException = false);
|
||||
virtual bool canSetProperty(Context *ctx, String *name);
|
||||
virtual bool hasProperty(Context *ctx, String *name) const;
|
||||
virtual bool deleteProperty(Context *ctx, String *name, bool flag);
|
||||
virtual void defineOwnProperty(Context *ctx, const Value &getter, const Value &setter, bool flag = false);
|
||||
virtual bool defineOwnProperty(Context *ctx, String *name, const Value &getter, const Value &setter, bool flag = false);
|
||||
|
||||
//
|
||||
// helpers
|
||||
|
@ -359,7 +409,7 @@ struct ArrayObject: Object {
|
|||
ArrayObject(const Array &value): value(value) {}
|
||||
virtual QString className() { return QStringLiteral("Array"); }
|
||||
virtual ArrayObject *asArrayObject() { return this; }
|
||||
virtual Value getProperty(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual Value getProperty(Context *ctx, String *name);
|
||||
};
|
||||
|
||||
struct FunctionObject: Object {
|
||||
|
@ -412,7 +462,7 @@ struct RegExpObject: Object {
|
|||
RegExpObject(const QRegularExpression &value, bool global): value(value), lastIndex(Value::fromInt32(0)), global(global) {}
|
||||
virtual QString className() { return QStringLiteral("RegExp"); }
|
||||
virtual RegExpObject *asRegExpObject() { return this; }
|
||||
virtual Value getProperty(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual Value getProperty(Context *ctx, String *name);
|
||||
};
|
||||
|
||||
struct ErrorObject: Object {
|
||||
|
@ -428,7 +478,7 @@ struct ActivationObject: Object {
|
|||
ActivationObject(Context *context): context(context), arguments(Value::undefinedValue()) {}
|
||||
virtual QString className() { return QStringLiteral("Activation"); }
|
||||
virtual ActivationObject *asActivationObject() { return this; }
|
||||
virtual Value *getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual PropertyDescriptor *getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill);
|
||||
};
|
||||
|
||||
struct ArgumentsObject: Object {
|
||||
|
@ -436,8 +486,8 @@ struct ArgumentsObject: Object {
|
|||
ArgumentsObject(Context *context): context(context) {}
|
||||
virtual QString className() { return QStringLiteral("Arguments"); }
|
||||
virtual ArgumentsObject *asArgumentsObject() { return this; }
|
||||
virtual Value getProperty(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual Value *getPropertyDescriptor(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual Value getProperty(Context *ctx, String *name);
|
||||
virtual PropertyDescriptor *getPropertyDescriptor(Context *ctx, String *name, PropertyDescriptor *to_fill);
|
||||
};
|
||||
|
||||
struct ExecutionEngine
|
||||
|
|
|
@ -235,11 +235,6 @@ Value Value::property(Context *ctx, String *name) const
|
|||
return isObject() ? objectValue()->getProperty(ctx, name) : undefinedValue();
|
||||
}
|
||||
|
||||
Value *Value::getPropertyDescriptor(Context *ctx, String *name) const
|
||||
{
|
||||
return isObject() ? objectValue()->getPropertyDescriptor(ctx, name) : 0;
|
||||
}
|
||||
|
||||
void Context::init(ExecutionEngine *eng)
|
||||
{
|
||||
engine = eng;
|
||||
|
@ -261,8 +256,9 @@ Value *Context::lookupPropertyDescriptor(String *name)
|
|||
{
|
||||
for (Context *ctx = this; ctx; ctx = ctx->parent) {
|
||||
if (ctx->activation.isObject()) {
|
||||
if (Value *prop = ctx->activation.objectValue()->getPropertyDescriptor(this, name)) {
|
||||
return prop;
|
||||
PropertyDescriptor tmp;
|
||||
if (PropertyDescriptor *pd = ctx->activation.objectValue()->getPropertyDescriptor(this, name, &tmp)) {
|
||||
return &pd->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,16 +66,9 @@ enum TypeHint {
|
|||
STRING_HINT
|
||||
};
|
||||
|
||||
enum PropertyAttributes {
|
||||
NoAttributes = 0,
|
||||
ValueAttribute = 1,
|
||||
WritableAttribute = 2,
|
||||
EnumerableAttribute = 4,
|
||||
ConfigurableAttribute = 8
|
||||
};
|
||||
|
||||
struct Object;
|
||||
struct String;
|
||||
struct PropertyDescriptor;
|
||||
struct Context;
|
||||
struct FunctionObject;
|
||||
struct BooleanObject;
|
||||
|
@ -248,7 +241,6 @@ struct Value
|
|||
ActivationObject *asArgumentsObject() const;
|
||||
|
||||
Value property(Context *ctx, String *name) const;
|
||||
Value *getPropertyDescriptor(Context *ctx, String *name) const;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -530,11 +530,11 @@ void ObjectCtor::call(Context *ctx)
|
|||
ctx->result = Value::fromObject(ctx->engine->newObject());
|
||||
}
|
||||
|
||||
Value ObjectCtor::getProperty(Context *ctx, String *name, PropertyAttributes *attributes)
|
||||
Value ObjectCtor::getProperty(Context *ctx, String *name)
|
||||
{
|
||||
if (name == ctx->engine->id_length)
|
||||
return Value::fromDouble(1);
|
||||
return Object::getProperty(ctx, name, attributes);
|
||||
return Object::getProperty(ctx, name);
|
||||
}
|
||||
|
||||
void ObjectPrototype::init(Context *ctx, const Value &ctor)
|
||||
|
@ -586,9 +586,9 @@ void ObjectPrototype::method_getOwnPropertyNames(Context *ctx)
|
|||
else {
|
||||
ArrayObject *array = ctx->engine->newArrayObject()->asArrayObject();
|
||||
Array &a = array->value;
|
||||
if (Table *members = O.objectValue()->members) {
|
||||
for (Property **it = members->begin(), **end = members->end(); it != end; ++it) {
|
||||
if (Property *prop = *it) {
|
||||
if (PropertyTable *members = O.objectValue()->members) {
|
||||
for (PropertyTableEntry **it = members->begin(), **end = members->end(); it != end; ++it) {
|
||||
if (PropertyTableEntry *prop = *it) {
|
||||
a.push(Value::fromString(prop->name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ struct ObjectCtor: FunctionObject
|
|||
|
||||
virtual void construct(Context *ctx);
|
||||
virtual void call(Context *ctx);
|
||||
virtual Value getProperty(Context *ctx, String *name, PropertyAttributes *attributes);
|
||||
virtual Value getProperty(Context *ctx, String *name);
|
||||
};
|
||||
|
||||
struct ObjectPrototype: Object
|
||||
|
|
Loading…
Reference in New Issue