mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Implement setIndexedPropertyHandler for ObjectTemplate
* rename data related to PropertyHandler * refactoring ObjectWithPropertyHandler to handle NamedProperty and IndexedProperty both * add cctest Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
This commit is contained in:
parent
fa052c8902
commit
ab15bd5574
5 changed files with 618 additions and 140 deletions
|
|
@ -3565,14 +3565,24 @@ ObjectTemplateRef* ObjectTemplateRef::create()
|
|||
return toRef(new ObjectTemplate());
|
||||
}
|
||||
|
||||
void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data)
|
||||
void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
|
||||
{
|
||||
toImpl(this)->setNamedPropertyHandler(data);
|
||||
}
|
||||
|
||||
void ObjectTemplateRef::removePropertyHandler()
|
||||
void ObjectTemplateRef::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
|
||||
{
|
||||
toImpl(this)->removePropertyHandler();
|
||||
toImpl(this)->setIndexedPropertyHandler(data);
|
||||
}
|
||||
|
||||
void ObjectTemplateRef::removeNamedPropertyHandler()
|
||||
{
|
||||
toImpl(this)->removeNamedPropertyHandler();
|
||||
}
|
||||
|
||||
void ObjectTemplateRef::removeIndexedPropertyHandler()
|
||||
{
|
||||
toImpl(this)->removeIndexedPropertyHandler();
|
||||
}
|
||||
|
||||
OptionalRef<FunctionTemplateRef> ObjectTemplateRef::constructor()
|
||||
|
|
|
|||
|
|
@ -1728,45 +1728,53 @@ public:
|
|||
void* instanceExtraData();
|
||||
};
|
||||
|
||||
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
typedef OptionalRef<ValueRef> (*PropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
// if intercepted you may returns non-empty value.
|
||||
// the returned value will be use futuer operation(you can return true, or false)
|
||||
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
|
||||
enum TemplatePropertyAttribute {
|
||||
TemplatePropertyAttributeNotExist = 1 << 0,
|
||||
TemplatePropertyAttributeExist = 1 << 1,
|
||||
TemplatePropertyAttributeWritable = 1 << 2,
|
||||
TemplatePropertyAttributeEnumerable = 1 << 3,
|
||||
TemplatePropertyAttributeConfigurable = 1 << 4,
|
||||
typedef OptionalRef<ValueRef> (*PropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
|
||||
enum class ObjectTemplatePropertyAttribute : uint8_t {
|
||||
PropertyAttributeNotExist = 1 << 0,
|
||||
PropertyAttributeExist = 1 << 1,
|
||||
PropertyAttributeWritable = 1 << 2,
|
||||
PropertyAttributeEnumerable = 1 << 3,
|
||||
PropertyAttributeConfigurable = 1 << 4,
|
||||
};
|
||||
typedef TemplatePropertyAttribute (*TemplatePropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
inline bool operator&(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
|
||||
{
|
||||
return static_cast<uint8_t>(a) & static_cast<uint8_t>(b);
|
||||
}
|
||||
inline ObjectTemplatePropertyAttribute operator|(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
|
||||
{
|
||||
return static_cast<ObjectTemplatePropertyAttribute>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
|
||||
}
|
||||
typedef ObjectTemplatePropertyAttribute (*PropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
// if intercepted you may returns non-empty value.
|
||||
// the returned value will be use futuer operation(you can return true, or false)
|
||||
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
typedef ValueVectorRef* (*TemplatePropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
|
||||
typedef OptionalRef<ValueRef> (*PropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
typedef ValueVectorRef* (*PropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
|
||||
// if intercepted you may returns non-empty value.
|
||||
// the returned value will be use futuer operation(you can return true, or false)
|
||||
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
|
||||
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
typedef OptionalRef<ValueRef> (*PropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
|
||||
typedef OptionalRef<ValueRef> (*PropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
|
||||
|
||||
struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerData {
|
||||
TemplatePropertyHandlerGetterCallback getter;
|
||||
TemplatePropertyHandlerSetterCallback setter;
|
||||
TemplatePropertyHandlerQueryCallback query;
|
||||
TemplatePropertyHandlerDeleteCallback deleter;
|
||||
TemplatePropertyHandlerEnumerationCallback enumerator;
|
||||
TemplatePropertyHandlerDefineOwnPropertyCallback definer;
|
||||
TemplatePropertyHandlerGetPropertyDescriptorCallback descriptor;
|
||||
void* data;
|
||||
struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerConfiguration {
|
||||
PropertyHandlerGetterCallback getter;
|
||||
PropertyHandlerSetterCallback setter;
|
||||
PropertyHandlerQueryCallback query;
|
||||
PropertyHandlerDeleteCallback deleter;
|
||||
PropertyHandlerEnumerationCallback enumerator;
|
||||
PropertyHandlerDefineOwnPropertyCallback definer;
|
||||
PropertyHandlerGetPropertyDescriptorCallback descriptor;
|
||||
void* data; // this data member is guaranteed to be kept in GC heap
|
||||
|
||||
ObjectTemplatePropertyHandlerData(
|
||||
TemplatePropertyHandlerGetterCallback getter = nullptr,
|
||||
TemplatePropertyHandlerSetterCallback setter = nullptr,
|
||||
TemplatePropertyHandlerQueryCallback query = nullptr,
|
||||
TemplatePropertyHandlerDeleteCallback deleter = nullptr,
|
||||
TemplatePropertyHandlerEnumerationCallback enumerator = nullptr,
|
||||
TemplatePropertyHandlerDefineOwnPropertyCallback definer = nullptr,
|
||||
TemplatePropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
|
||||
ObjectTemplatePropertyHandlerConfiguration(
|
||||
PropertyHandlerGetterCallback getter = nullptr,
|
||||
PropertyHandlerSetterCallback setter = nullptr,
|
||||
PropertyHandlerQueryCallback query = nullptr,
|
||||
PropertyHandlerDeleteCallback deleter = nullptr,
|
||||
PropertyHandlerEnumerationCallback enumerator = nullptr,
|
||||
PropertyHandlerDefineOwnPropertyCallback definer = nullptr,
|
||||
PropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
|
||||
void* data = nullptr)
|
||||
: getter(getter)
|
||||
, setter(setter)
|
||||
|
|
@ -1790,8 +1798,10 @@ public:
|
|||
class ESCARGOT_EXPORT ObjectTemplateRef : public TemplateRef {
|
||||
public:
|
||||
static ObjectTemplateRef* create();
|
||||
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data);
|
||||
void removePropertyHandler();
|
||||
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
|
||||
void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
|
||||
void removeNamedPropertyHandler();
|
||||
void removeIndexedPropertyHandler();
|
||||
|
||||
// returns function template if object template is instance template of function template
|
||||
OptionalRef<FunctionTemplateRef> constructor();
|
||||
|
|
|
|||
|
|
@ -29,21 +29,69 @@
|
|||
|
||||
namespace Escargot {
|
||||
|
||||
class ObjectTemplatePropertyHandlerData : public gc {
|
||||
friend class ObjectWithPropertyHandler;
|
||||
|
||||
public:
|
||||
explicit ObjectTemplatePropertyHandlerData(const ObjectTemplatePropertyHandlerConfiguration& data)
|
||||
: m_getter(data.getter)
|
||||
, m_setter(data.setter)
|
||||
, m_query(data.query)
|
||||
, m_deleter(data.deleter)
|
||||
, m_enumerator(data.enumerator)
|
||||
, m_definer(data.definer)
|
||||
, m_descriptor(data.descriptor)
|
||||
, m_data(data.data)
|
||||
{
|
||||
}
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
static MAY_THREAD_LOCAL bool typeInited = false;
|
||||
static MAY_THREAD_LOCAL GC_descr descr;
|
||||
if (!typeInited) {
|
||||
// only mark m_data
|
||||
GC_word obj_bitmap[GC_BITMAP_SIZE(ObjectTemplatePropertyHandlerData)] = { 0 };
|
||||
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ObjectTemplatePropertyHandlerData, m_data));
|
||||
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ObjectTemplatePropertyHandlerData));
|
||||
typeInited = true;
|
||||
}
|
||||
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
|
||||
}
|
||||
|
||||
private:
|
||||
PropertyHandlerGetterCallback m_getter;
|
||||
PropertyHandlerSetterCallback m_setter;
|
||||
PropertyHandlerQueryCallback m_query;
|
||||
PropertyHandlerDeleteCallback m_deleter;
|
||||
PropertyHandlerEnumerationCallback m_enumerator;
|
||||
PropertyHandlerDefineOwnPropertyCallback m_definer;
|
||||
PropertyHandlerGetPropertyDescriptorCallback m_descriptor;
|
||||
void* m_data;
|
||||
};
|
||||
|
||||
class ObjectWithPropertyHandler : public Object {
|
||||
public:
|
||||
virtual bool isValidPropertyName(const ObjectPropertyName& P) = 0;
|
||||
ObjectWithPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* namedData, ObjectTemplatePropertyHandlerData* indexedData)
|
||||
: Object(structure, std::move(values), proto)
|
||||
, m_namedPropertyHandler(namedData)
|
||||
, m_indexedPropertyHandler(indexedData)
|
||||
{
|
||||
ASSERT(namedData || indexedData);
|
||||
}
|
||||
|
||||
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
|
||||
{
|
||||
if (isValidPropertyName(P) && m_propertyHandler->getter) {
|
||||
auto ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_getter) {
|
||||
auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
|
||||
if (ret.hasValue()) {
|
||||
if (m_propertyHandler->query) {
|
||||
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
if (propertyHandler->m_query) {
|
||||
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
|
||||
return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
} else {
|
||||
return ObjectGetResult(toImpl(ret.value()), true, true, true);
|
||||
}
|
||||
|
|
@ -55,8 +103,9 @@ public:
|
|||
|
||||
virtual Value getOwnPropertyDescriptor(ExecutionState& state, const ObjectPropertyName& P) override
|
||||
{
|
||||
if (isValidPropertyName(P) && m_propertyHandler->descriptor) {
|
||||
auto ret = m_propertyHandler->descriptor(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_descriptor) {
|
||||
auto ret = propertyHandler->m_descriptor(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
if (ret.hasValue()) {
|
||||
return toImpl(ret.value());
|
||||
|
|
@ -68,14 +117,15 @@ public:
|
|||
|
||||
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) override
|
||||
{
|
||||
if (isValidPropertyName(P)) {
|
||||
if (m_propertyHandler->definer) {
|
||||
auto ret = m_propertyHandler->definer(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data, toRef(P.toPlainValue()), ObjectPropertyDescriptorRef((void*)&desc));
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler) {
|
||||
if (propertyHandler->m_definer) {
|
||||
auto ret = propertyHandler->m_definer(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), ObjectPropertyDescriptorRef((void*)&desc));
|
||||
if (ret.hasValue()) {
|
||||
return ret.value()->toBoolean(toRef(&state));
|
||||
}
|
||||
} else if (m_propertyHandler->setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
|
||||
auto ret = m_propertyHandler->setter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data, toRef(P.toPlainValue()), toRef(desc.value()));
|
||||
} else if (propertyHandler->m_setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
|
||||
auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(desc.value()));
|
||||
if (ret.hasValue()) {
|
||||
return ret.value()->toBoolean(toRef(&state));
|
||||
}
|
||||
|
|
@ -87,10 +137,11 @@ public:
|
|||
|
||||
virtual bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
|
||||
{
|
||||
if (isValidPropertyName(P) && m_propertyHandler->query) {
|
||||
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_query) {
|
||||
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
return attr & TemplatePropertyAttributeExist;
|
||||
return attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist;
|
||||
}
|
||||
|
||||
return Object::hasOwnProperty(state, P);
|
||||
|
|
@ -98,18 +149,19 @@ public:
|
|||
|
||||
virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override
|
||||
{
|
||||
if (isValidPropertyName(P)) {
|
||||
if (m_propertyHandler->query) {
|
||||
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler) {
|
||||
if (propertyHandler->m_query) {
|
||||
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
if (attr & TemplatePropertyAttributeExist) {
|
||||
bool isWritable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable;
|
||||
bool isEnumerable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable;
|
||||
bool isConfigurable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable;
|
||||
if (attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist) {
|
||||
bool isWritable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable;
|
||||
bool isEnumerable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable;
|
||||
bool isConfigurable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable;
|
||||
|
||||
Value v;
|
||||
if (m_propertyHandler->getter) {
|
||||
OptionalRef<ValueRef> ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
if (propertyHandler->m_getter) {
|
||||
OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
if (ret.hasValue()) {
|
||||
v = toImpl(ret.value());
|
||||
|
|
@ -119,8 +171,8 @@ public:
|
|||
ObjectHasPropertyResult result(ObjectGetResult(v, isWritable, isEnumerable, isConfigurable));
|
||||
return result;
|
||||
}
|
||||
} else if (m_propertyHandler->getter) {
|
||||
OptionalRef<ValueRef> ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
} else if (propertyHandler->m_getter) {
|
||||
OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
if (ret.hasValue()) {
|
||||
return ObjectGetResult(toImpl(ret.value()), true, true, true);
|
||||
|
|
@ -133,8 +185,9 @@ public:
|
|||
|
||||
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
|
||||
{
|
||||
if (isValidPropertyName(P) && m_propertyHandler->deleter) {
|
||||
auto ret = m_propertyHandler->deleter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_deleter) {
|
||||
auto ret = propertyHandler->m_deleter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
if (ret.hasValue()) {
|
||||
return ret.value()->toBoolean(toRef(&state));
|
||||
|
|
@ -146,35 +199,40 @@ public:
|
|||
|
||||
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) override
|
||||
{
|
||||
if (m_propertyHandler->enumerator) {
|
||||
auto ret = m_propertyHandler->enumerator(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data);
|
||||
if (m_propertyHandler->query) {
|
||||
for (size_t i = 0; i < ret->size(); i++) {
|
||||
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
|
||||
continue;
|
||||
}
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = m_namedPropertyHandler;
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
if (propertyHandler && propertyHandler->m_enumerator) {
|
||||
auto ret = propertyHandler->m_enumerator(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data);
|
||||
if (propertyHandler->m_query) {
|
||||
for (size_t i = 0; i < ret->size(); i++) {
|
||||
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
|
||||
ret->at(i));
|
||||
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
|
||||
ret->at(i));
|
||||
|
||||
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
|
||||
(ObjectStructurePropertyDescriptor::PresentAttribute)(
|
||||
((attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
|
||||
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
|
||||
return;
|
||||
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
|
||||
(ObjectStructurePropertyDescriptor::PresentAttribute)(
|
||||
((attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
|
||||
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < ret->size(); i++) {
|
||||
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
|
||||
continue;
|
||||
}
|
||||
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
|
||||
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
|
||||
return;
|
||||
} else {
|
||||
for (size_t i = 0; i < ret->size(); i++) {
|
||||
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
|
||||
continue;
|
||||
}
|
||||
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
|
||||
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
propertyHandler = m_indexedPropertyHandler;
|
||||
}
|
||||
|
||||
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
|
||||
|
|
@ -182,15 +240,16 @@ public:
|
|||
|
||||
virtual ObjectGetResult get(ExecutionState& state, const ObjectPropertyName& P, const Value& receiver) override
|
||||
{
|
||||
if (isValidPropertyName(P)) {
|
||||
auto ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data,
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_getter) {
|
||||
auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
|
||||
if (ret.hasValue()) {
|
||||
if (m_propertyHandler->query) {
|
||||
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data,
|
||||
if (propertyHandler->m_query) {
|
||||
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
|
||||
toRef(P.toPlainValue()));
|
||||
return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
|
||||
return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
} else {
|
||||
return ObjectGetResult(toImpl(ret.value()), true, true, true);
|
||||
}
|
||||
|
|
@ -202,8 +261,9 @@ public:
|
|||
|
||||
virtual bool set(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver) override
|
||||
{
|
||||
if (isValidPropertyName(P) && m_propertyHandler->setter) {
|
||||
auto ret = m_propertyHandler->setter(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data, toRef(P.toPlainValue()), toRef(v));
|
||||
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
|
||||
if (propertyHandler && propertyHandler->m_setter) {
|
||||
auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(v));
|
||||
if (ret.hasValue()) {
|
||||
return ret.value()->toBoolean(toRef(&state));
|
||||
}
|
||||
|
|
@ -222,28 +282,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectWithPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* data)
|
||||
: Object(structure, std::move(values), proto)
|
||||
, m_propertyHandler(data)
|
||||
{
|
||||
ASSERT(!!m_propertyHandler);
|
||||
}
|
||||
|
||||
ObjectTemplatePropertyHandlerData* m_propertyHandler;
|
||||
};
|
||||
|
||||
class ObjectWithNamedPropertyHandler : public ObjectWithPropertyHandler {
|
||||
public:
|
||||
ObjectWithNamedPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* data)
|
||||
: ObjectWithPropertyHandler(structure, std::forward<ObjectPropertyValueVector>(values), proto, data)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool isValidPropertyName(const ObjectPropertyName& P) override
|
||||
{
|
||||
return !P.isIndexString();
|
||||
}
|
||||
private:
|
||||
ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
|
||||
ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
|
||||
};
|
||||
|
||||
void* ObjectTemplate::operator new(size_t size)
|
||||
|
|
@ -254,7 +295,8 @@ void* ObjectTemplate::operator new(size_t size)
|
|||
GC_word objBitmap[GC_BITMAP_SIZE(ObjectTemplate)] = { 0 };
|
||||
Template::fillGCDescriptor(objBitmap);
|
||||
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_constructor));
|
||||
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_propertyHandler));
|
||||
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_namedPropertyHandler));
|
||||
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_indexedPropertyHandler));
|
||||
descr = GC_make_descriptor(objBitmap, GC_WORD_LEN(ObjectTemplate));
|
||||
typeInited = true;
|
||||
}
|
||||
|
|
@ -263,7 +305,8 @@ void* ObjectTemplate::operator new(size_t size)
|
|||
|
||||
ObjectTemplate::ObjectTemplate(Optional<FunctionTemplate*> constructor)
|
||||
: m_constructor(constructor)
|
||||
, m_propertyHandler(nullptr)
|
||||
, m_namedPropertyHandler(nullptr)
|
||||
, m_indexedPropertyHandler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -289,8 +332,8 @@ Object* ObjectTemplate::instantiate(Context* ctx)
|
|||
proto = ctx->globalObject()->objectPrototype();
|
||||
}
|
||||
|
||||
if (m_propertyHandler) {
|
||||
result = new ObjectWithNamedPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_propertyHandler);
|
||||
if (m_namedPropertyHandler || m_indexedPropertyHandler) {
|
||||
result = new ObjectWithPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_namedPropertyHandler, m_indexedPropertyHandler);
|
||||
} else {
|
||||
result = new Object(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto);
|
||||
}
|
||||
|
|
@ -372,16 +415,29 @@ bool ObjectTemplate::installTo(Context* ctx, Object* target)
|
|||
return result.error.isEmpty();
|
||||
}
|
||||
|
||||
void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data)
|
||||
void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
|
||||
{
|
||||
ASSERT(!m_propertyHandler);
|
||||
m_propertyHandler = new (GC) ObjectTemplatePropertyHandlerData(data);
|
||||
ASSERT(!m_namedPropertyHandler);
|
||||
m_namedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
|
||||
}
|
||||
|
||||
void ObjectTemplate::removePropertyHandler()
|
||||
void ObjectTemplate::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
|
||||
{
|
||||
ASSERT(!m_propertyHandler);
|
||||
GC_FREE(m_propertyHandler);
|
||||
m_propertyHandler = nullptr;
|
||||
ASSERT(!m_indexedPropertyHandler);
|
||||
m_indexedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
|
||||
}
|
||||
|
||||
void ObjectTemplate::removeNamedPropertyHandler()
|
||||
{
|
||||
// just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
|
||||
ASSERT(!m_namedPropertyHandler);
|
||||
m_namedPropertyHandler = nullptr;
|
||||
}
|
||||
|
||||
void ObjectTemplate::removeIndexedPropertyHandler()
|
||||
{
|
||||
// just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
|
||||
ASSERT(!m_indexedPropertyHandler);
|
||||
m_indexedPropertyHandler = nullptr;
|
||||
}
|
||||
} // namespace Escargot
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@
|
|||
namespace Escargot {
|
||||
|
||||
class FunctionTemplate;
|
||||
struct ObjectTemplatePropertyHandlerData;
|
||||
class ObjectTemplatePropertyHandlerData;
|
||||
struct ObjectTemplatePropertyHandlerConfiguration;
|
||||
|
||||
class ObjectTemplate : public Template {
|
||||
public:
|
||||
|
|
@ -50,12 +51,15 @@ public:
|
|||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size) = delete;
|
||||
|
||||
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data);
|
||||
void removePropertyHandler();
|
||||
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
|
||||
void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
|
||||
void removeNamedPropertyHandler();
|
||||
void removeIndexedPropertyHandler();
|
||||
|
||||
private:
|
||||
Optional<FunctionTemplate*> m_constructor;
|
||||
ObjectTemplatePropertyHandlerData* m_propertyHandler;
|
||||
ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
|
||||
ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
|
||||
};
|
||||
} // namespace Escargot
|
||||
|
||||
|
|
|
|||
|
|
@ -743,7 +743,7 @@ TEST(ObjectTemplate, Basic4)
|
|||
{
|
||||
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
|
||||
|
||||
ObjectTemplatePropertyHandlerData handler;
|
||||
ObjectTemplatePropertyHandlerConfiguration handler;
|
||||
handler.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
|
||||
return (ValueRef*)self->extraData();
|
||||
|
|
@ -768,14 +768,14 @@ TEST(ObjectTemplate, Basic4)
|
|||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> TemplatePropertyAttribute {
|
||||
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
|
||||
return (TemplatePropertyAttribute)(TemplatePropertyAttribute::TemplatePropertyAttributeWritable | TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable | TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
}
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
|
||||
return (TemplatePropertyAttribute)(TemplatePropertyAttribute::TemplatePropertyAttributeWritable);
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
|
||||
}
|
||||
return TemplatePropertyAttribute::TemplatePropertyAttributeNotExist;
|
||||
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
|
||||
};
|
||||
|
||||
handler.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
|
||||
|
|
@ -861,7 +861,7 @@ TEST(ObjectTemplate, Basic4)
|
|||
|
||||
|
||||
ObjectTemplateRef* tpl2 = ObjectTemplateRef::create();
|
||||
ObjectTemplatePropertyHandlerData handler2;
|
||||
ObjectTemplatePropertyHandlerConfiguration handler2;
|
||||
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
|
@ -883,6 +883,404 @@ TEST(ObjectTemplate, Basic4)
|
|||
obj);
|
||||
}
|
||||
|
||||
TEST(ObjectTemplate, Basic5)
|
||||
{
|
||||
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
|
||||
|
||||
ObjectTemplatePropertyHandlerConfiguration handler;
|
||||
handler.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
return (ValueRef*)self->extraData();
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
return ValueRef::create(555.555);
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
self->setExtraData(value);
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
self->setExtraData(ValueRef::create(123));
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
|
||||
}
|
||||
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
|
||||
};
|
||||
|
||||
handler.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
|
||||
ValueVectorRef* v = ValueVectorRef::create(2);
|
||||
v->set(0, StringRef::createFromASCII("1"));
|
||||
v->set(1, ValueRef::create(3));
|
||||
return v;
|
||||
};
|
||||
|
||||
handler.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 4) {
|
||||
return OptionalRef<ValueRef>(ValueRef::create(false));
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 5) {
|
||||
ObjectRef* desc = ObjectRef::create(state);
|
||||
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
|
||||
return desc;
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
tpl->setIndexedPropertyHandler(handler);
|
||||
|
||||
ObjectRef* obj = tpl->instantiate(g_context.get());
|
||||
obj->setExtraData(ValueRef::create(123));
|
||||
|
||||
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
|
||||
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("1"), ValueRef::createNull()));
|
||||
ValueRef* one = obj->get(state, ValueRef::create(1));
|
||||
EXPECT_TRUE(one->isNull());
|
||||
|
||||
ValueRef* two = obj->get(state, ValueRef::create(2));
|
||||
EXPECT_TRUE(two->isUndefined());
|
||||
|
||||
EXPECT_TRUE(obj->defineDataProperty(state, ValueRef::create(3), ValueRef::create(333), true, true, true));
|
||||
ValueRef* threeResult = obj->get(state, StringRef::createFromASCII("1"));
|
||||
EXPECT_TRUE(threeResult->equalsTo(state, ValueRef::create(123)));
|
||||
|
||||
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("1"));
|
||||
|
||||
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
|
||||
|
||||
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("3"));
|
||||
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
|
||||
|
||||
int pcnt = 0;
|
||||
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
|
||||
if (pcnt == 0) {
|
||||
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 1);
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(isEnumerable);
|
||||
EXPECT_TRUE(isConfigurable);
|
||||
} else if (pcnt == 1) {
|
||||
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 3);
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(!isEnumerable);
|
||||
EXPECT_TRUE(!isConfigurable);
|
||||
}
|
||||
pcnt++;
|
||||
return true;
|
||||
});
|
||||
|
||||
EXPECT_TRUE(pcnt == 2);
|
||||
|
||||
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("6")));
|
||||
EXPECT_FALSE(obj->deleteOwnProperty(state, ValueRef::create(4)));
|
||||
|
||||
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("5"));
|
||||
EXPECT_TRUE(descObj->isObject());
|
||||
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
|
||||
|
||||
return ValueRef::createUndefined();
|
||||
},
|
||||
obj);
|
||||
|
||||
|
||||
ObjectTemplateRef* tpl2 = ObjectTemplateRef::create();
|
||||
ObjectTemplatePropertyHandlerConfiguration handler2;
|
||||
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
handler2.definer = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 100) {
|
||||
return OptionalRef<ValueRef>(ValueRef::create(false));
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
tpl2->setIndexedPropertyHandler(handler2);
|
||||
|
||||
obj = tpl2->instantiate(g_context.get());
|
||||
|
||||
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
|
||||
EXPECT_FALSE(obj->defineDataProperty(state, StringRef::createFromASCII("100"), ValueRef::create(111), false, false, false));
|
||||
return ValueRef::createUndefined();
|
||||
},
|
||||
obj);
|
||||
}
|
||||
|
||||
TEST(ObjectTemplate, Basic6)
|
||||
{
|
||||
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
|
||||
|
||||
ObjectTemplatePropertyHandlerConfiguration handler1;
|
||||
handler1.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
|
||||
return (ValueRef*)self->extraData();
|
||||
}
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
|
||||
return ValueRef::create(555.555);
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler1.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
|
||||
self->setExtraData(value);
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
|
||||
self->setExtraData(ValueRef::create(123));
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler1.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
}
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
|
||||
}
|
||||
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
|
||||
};
|
||||
|
||||
handler1.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
|
||||
ValueVectorRef* v = ValueVectorRef::create(2);
|
||||
v->set(0, StringRef::createFromASCII("aaa"));
|
||||
v->set(1, StringRef::createFromASCII("ccc"));
|
||||
return v;
|
||||
};
|
||||
|
||||
handler1.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ddd", 3)) {
|
||||
return OptionalRef<ValueRef>(ValueRef::create(false));
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler1.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("eee", 3)) {
|
||||
ObjectRef* desc = ObjectRef::create(state);
|
||||
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
|
||||
return desc;
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
ObjectTemplatePropertyHandlerConfiguration handler2;
|
||||
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
return (ValueRef*)self->extraData();
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
return ValueRef::create(555.555);
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler2.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
self->setExtraData(value);
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
self->setExtraData(ValueRef::create(123));
|
||||
return OptionalRef<ValueRef>(ValueRef::create(true));
|
||||
}
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler2.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 1) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
|
||||
}
|
||||
if (indexProperty == 3) {
|
||||
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
|
||||
}
|
||||
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
|
||||
};
|
||||
|
||||
handler2.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
|
||||
ValueVectorRef* v = ValueVectorRef::create(2);
|
||||
v->set(0, StringRef::createFromASCII("1"));
|
||||
v->set(1, ValueRef::create(3));
|
||||
return v;
|
||||
};
|
||||
|
||||
handler2.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 4) {
|
||||
return OptionalRef<ValueRef>(ValueRef::create(false));
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
handler2.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
|
||||
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
|
||||
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
|
||||
if (indexProperty == 5) {
|
||||
ObjectRef* desc = ObjectRef::create(state);
|
||||
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
|
||||
return desc;
|
||||
}
|
||||
|
||||
return OptionalRef<ValueRef>();
|
||||
};
|
||||
|
||||
tpl->setNamedPropertyHandler(handler1);
|
||||
tpl->setIndexedPropertyHandler(handler2);
|
||||
|
||||
ObjectRef* obj = tpl->instantiate(g_context.get());
|
||||
obj->setExtraData(ValueRef::create(123));
|
||||
|
||||
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
|
||||
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("aaa"), ValueRef::createNull()));
|
||||
ValueRef* aaa = obj->get(state, StringRef::createFromASCII("aaa"));
|
||||
EXPECT_TRUE(aaa->isNull());
|
||||
|
||||
ValueRef* bbb = obj->get(state, StringRef::createFromASCII("bbb"));
|
||||
EXPECT_TRUE(bbb->isUndefined());
|
||||
|
||||
EXPECT_TRUE(obj->defineDataProperty(state, StringRef::createFromASCII("ccc"), ValueRef::create(333), true, true, true));
|
||||
ValueRef* cccResult = obj->get(state, StringRef::createFromASCII("aaa"));
|
||||
EXPECT_TRUE(cccResult->equalsTo(state, ValueRef::create(123)));
|
||||
|
||||
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("aaa"));
|
||||
|
||||
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
|
||||
|
||||
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("ccc"));
|
||||
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
|
||||
|
||||
int pcnt = 0;
|
||||
// FIXME enumration operation
|
||||
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
|
||||
if (pcnt == 0) {
|
||||
EXPECT_TRUE(propertyName->toString(state)->toStdUTF8String() == "aaa");
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(isEnumerable);
|
||||
EXPECT_TRUE(isConfigurable);
|
||||
} else if (pcnt == 1) {
|
||||
EXPECT_TRUE(propertyName->toString(state)->toStdUTF8String() == "ccc");
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(!isEnumerable);
|
||||
EXPECT_TRUE(!isConfigurable);
|
||||
}
|
||||
pcnt++;
|
||||
return true;
|
||||
});
|
||||
|
||||
EXPECT_TRUE(pcnt == 4);
|
||||
|
||||
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("fff")));
|
||||
EXPECT_FALSE(obj->deleteOwnProperty(state, StringRef::createFromASCII("ddd")));
|
||||
|
||||
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("eee"));
|
||||
EXPECT_TRUE(descObj->isObject());
|
||||
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
|
||||
|
||||
return ValueRef::createUndefined();
|
||||
},
|
||||
obj);
|
||||
|
||||
obj->setExtraData(ValueRef::create(123));
|
||||
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
|
||||
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("1"), ValueRef::createNull()));
|
||||
ValueRef* one = obj->get(state, ValueRef::create(1));
|
||||
EXPECT_TRUE(one->isNull());
|
||||
|
||||
ValueRef* two = obj->get(state, ValueRef::create(2));
|
||||
EXPECT_TRUE(two->isUndefined());
|
||||
|
||||
EXPECT_TRUE(obj->defineDataProperty(state, ValueRef::create(3), ValueRef::create(333), true, true, true));
|
||||
ValueRef* threeResult = obj->get(state, StringRef::createFromASCII("1"));
|
||||
EXPECT_TRUE(threeResult->equalsTo(state, ValueRef::create(123)));
|
||||
|
||||
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("1"));
|
||||
|
||||
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
|
||||
|
||||
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("3"));
|
||||
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
|
||||
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
|
||||
|
||||
int pcnt = 0;
|
||||
// FIXME enumration operation
|
||||
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
|
||||
if (pcnt == 2) {
|
||||
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 1);
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(isEnumerable);
|
||||
EXPECT_TRUE(isConfigurable);
|
||||
} else if (pcnt == 3) {
|
||||
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 3);
|
||||
EXPECT_TRUE(isWritable);
|
||||
EXPECT_TRUE(!isEnumerable);
|
||||
EXPECT_TRUE(!isConfigurable);
|
||||
}
|
||||
pcnt++;
|
||||
return true;
|
||||
});
|
||||
|
||||
EXPECT_TRUE(pcnt == 4);
|
||||
|
||||
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("6")));
|
||||
EXPECT_FALSE(obj->deleteOwnProperty(state, ValueRef::create(4)));
|
||||
|
||||
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("5"));
|
||||
EXPECT_TRUE(descObj->isObject());
|
||||
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
|
||||
|
||||
return ValueRef::createUndefined();
|
||||
},
|
||||
obj);
|
||||
}
|
||||
|
||||
TEST(FunctionTemplate, Basic1)
|
||||
{
|
||||
auto ft = FunctionTemplateRef::create(AtomicStringRef::create(g_context.get(), "asdf"), 2, true, true, [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, OptionalRef<ObjectRef> newTarget) -> ValueRef* {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue