Fix some issues with the delete operator
Properly implement delete operator for identifiers and local variables. Change-Id: I8ac55edc80c31a94d11444c9f5c78caf4b131c95 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
parent
87b3179817
commit
15326415d1
|
@ -500,14 +500,9 @@ void __qmljs_llvm_delete_member(ExecutionContext *ctx, Value *result, Value *bas
|
|||
*result = __qmljs_delete_member(ctx, *base, name);
|
||||
}
|
||||
|
||||
void __qmljs_llvm_delete_property(ExecutionContext *ctx, Value *result, String *name)
|
||||
void __qmljs_llvm_delete_name(ExecutionContext *ctx, Value *result, String *name)
|
||||
{
|
||||
*result = __qmljs_delete_property(ctx, name);
|
||||
}
|
||||
|
||||
void __qmljs_llvm_delete_value(ExecutionContext *ctx, Value *result, Value *value)
|
||||
{
|
||||
*result = __qmljs_delete_value(ctx, *value);
|
||||
*result = __qmljs_delete_name(ctx, name);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
@ -262,11 +262,11 @@ VM::Value VME::operator()(QQmlJS::VM::ExecutionContext *context, const uchar *co
|
|||
MOTH_END_INSTR(CallBuiltinDeleteSubscript)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
|
||||
TEMP(instr.targetTempIndex) = __qmljs_delete_property(context, instr.name);
|
||||
TEMP(instr.targetTempIndex) = __qmljs_delete_name(context, instr.name);
|
||||
MOTH_END_INSTR(CallBuiltinDeleteName)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallBuiltinDeleteValue)
|
||||
TEMP(instr.targetTempIndex) = __qmljs_delete_value(context, TEMP(instr.tempIndex));
|
||||
TEMP(instr.targetTempIndex) = VM::Value::fromBoolean(false);
|
||||
MOTH_END_INSTR(CallBuiltinDeleteValue)
|
||||
|
||||
MOTH_BEGIN_INSTR(CreateValue)
|
||||
|
|
|
@ -221,6 +221,26 @@ PropertyDescriptor *ExecutionContext::lookupPropertyDescriptor(String *name, Pro
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool ExecutionContext::deleteProperty(String *name)
|
||||
{
|
||||
for (DeclarativeEnvironment *ctx = lexicalEnvironment; ctx; ctx = ctx->outer) {
|
||||
if (ctx->withObject) {
|
||||
DeclarativeEnvironment::With *w = ctx->withObject;
|
||||
while (w) {
|
||||
if (w->object->__hasProperty__(this, name))
|
||||
w->object->__delete__(this, name);
|
||||
w = w->next;
|
||||
}
|
||||
}
|
||||
if (ctx->activation) {
|
||||
if (ctx->activation->__hasProperty__(this, name))
|
||||
ctx->activation->__delete__(this, name);
|
||||
}
|
||||
}
|
||||
// ### throw syntax error in strict mode
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op)
|
||||
{
|
||||
for (DeclarativeEnvironment *ctx = lexicalEnvironment; ctx; ctx = ctx->outer) {
|
||||
|
|
|
@ -118,6 +118,7 @@ struct ExecutionContext
|
|||
|
||||
PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp);
|
||||
void inplaceBitOp(Value value, String *name, BinOp op);
|
||||
bool deleteProperty(String *name);
|
||||
|
||||
inline uint argumentCount() const { return variableEnvironment->argumentCount; }
|
||||
inline Value argument(unsigned int index = 0)
|
||||
|
|
|
@ -411,7 +411,7 @@ struct Object {
|
|||
virtual void __put__(ExecutionContext *ctx, String *name, const Value &value, bool throwException = false);
|
||||
virtual bool __canPut__(ExecutionContext *ctx, String *name);
|
||||
virtual bool __hasProperty__(ExecutionContext *ctx, String *name) const;
|
||||
virtual bool __delete__(ExecutionContext *ctx, String *name, bool throwException);
|
||||
virtual bool __delete__(ExecutionContext *ctx, String *name, bool throwException = false);
|
||||
virtual bool __defineOwnProperty__(ExecutionContext *ctx, String *name, PropertyDescriptor *desc, bool throwException = false);
|
||||
|
||||
//
|
||||
|
|
|
@ -195,18 +195,9 @@ Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name)
|
|||
return Value::fromBoolean(obj.objectValue()->__delete__(ctx, name, true));
|
||||
}
|
||||
|
||||
Value __qmljs_delete_property(ExecutionContext *ctx, String *name)
|
||||
Value __qmljs_delete_name(ExecutionContext *ctx, String *name)
|
||||
{
|
||||
Object *obj = ctx->lexicalEnvironment->activation;
|
||||
if (!obj)
|
||||
obj = ctx->engine->globalObject.objectValue();
|
||||
return Value::fromBoolean(obj->__delete__(ctx, name, true));
|
||||
}
|
||||
|
||||
Value __qmljs_delete_value(ExecutionContext *ctx, Value value)
|
||||
{
|
||||
Q_UNUSED(value);
|
||||
return __qmljs_throw_type_error(ctx); // ### throw syntax error
|
||||
return Value::fromBoolean(ctx->deleteProperty(name));
|
||||
}
|
||||
|
||||
Value __qmljs_add_helper(Value left, Value right, ExecutionContext *ctx)
|
||||
|
|
|
@ -177,8 +177,7 @@ Value __qmljs_not(Value value, ExecutionContext *ctx);
|
|||
|
||||
Value __qmljs_delete_subscript(ExecutionContext *ctx, Value base, Value index);
|
||||
Value __qmljs_delete_member(ExecutionContext *ctx, Value base, String *name);
|
||||
Value __qmljs_delete_property(ExecutionContext *ctx, String *name);
|
||||
Value __qmljs_delete_value(ExecutionContext *ctx, Value value);
|
||||
Value __qmljs_delete_name(ExecutionContext *ctx, String *name);
|
||||
|
||||
Value __qmljs_typeof(Value value, ExecutionContext *ctx);
|
||||
void __qmljs_throw(Value value, ExecutionContext *context);
|
||||
|
|
|
@ -230,9 +230,15 @@ void InstructionSelection::callActivationProperty(IR::Call *call, IR::Temp *resu
|
|||
} else if (IR::Subscript *ss = call->args->expr->asSubscript()) {
|
||||
generateFunctionCall(result, __qmljs_delete_subscript, ContextRegister, ss->base->asTemp(), ss->index->asTemp());
|
||||
return;
|
||||
} else {
|
||||
assert(!"builtin_delete: unimplemented");
|
||||
Q_UNIMPLEMENTED();
|
||||
} else if (IR::Name *n = call->args->expr->asName()) {
|
||||
generateFunctionCall(result, __qmljs_delete_name, ContextRegister, n);
|
||||
return;
|
||||
} else if (call->args->expr->asTemp()){
|
||||
// ### should throw in strict mode
|
||||
Address dest = loadTempAddress(ScratchRegister, result);
|
||||
Value v = Value::fromBoolean(false);
|
||||
storeValue(v, dest);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue