mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 10:22:05 -05:00
LibJS: Allow "delete someGlobalVariable"
This is solved by allowing Identifier nodes to produce a Reference with the global object as base.
This commit is contained in:
parent
67b8e6fc5b
commit
3c4a9e421f
6 changed files with 54 additions and 0 deletions
|
@ -382,6 +382,11 @@ Reference Expression::to_reference(Interpreter&) const
|
|||
return {};
|
||||
}
|
||||
|
||||
Reference Identifier::to_reference(Interpreter& interpreter) const
|
||||
{
|
||||
return interpreter.get_reference(string());
|
||||
}
|
||||
|
||||
Reference MemberExpression::to_reference(Interpreter& interpreter) const
|
||||
{
|
||||
auto object_value = m_object->execute(interpreter);
|
||||
|
@ -404,6 +409,8 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
|
|||
return {};
|
||||
if (reference.is_unresolvable())
|
||||
return Value(true);
|
||||
// FIXME: Support deleting locals
|
||||
ASSERT(!reference.is_local_variable());
|
||||
auto* base_object = reference.base().to_object(interpreter.heap());
|
||||
if (!base_object)
|
||||
return {};
|
||||
|
|
|
@ -516,6 +516,7 @@ public:
|
|||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual bool is_identifier() const override { return true; }
|
||||
virtual Reference to_reference(Interpreter&) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "Identifier"; }
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <LibJS/Runtime/MarkedValueList.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Reference.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
|
@ -163,6 +164,18 @@ Value Interpreter::get_variable(const FlyString& name)
|
|||
return global_object().get(name);
|
||||
}
|
||||
|
||||
Reference Interpreter::get_reference(const FlyString& name)
|
||||
{
|
||||
if (m_call_stack.size()) {
|
||||
for (auto* environment = current_environment(); environment; environment = environment->parent()) {
|
||||
auto possible_match = environment->get(name);
|
||||
if (possible_match.has_value())
|
||||
return { Reference::LocalVariable, name };
|
||||
}
|
||||
}
|
||||
return { &global_object(), PropertyName(name) };
|
||||
}
|
||||
|
||||
void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
|
||||
{
|
||||
roots.set(m_global_object);
|
||||
|
|
|
@ -96,6 +96,8 @@ public:
|
|||
Value get_variable(const FlyString& name);
|
||||
void set_variable(const FlyString& name, Value, bool first_assignment = false);
|
||||
|
||||
Reference get_reference(const FlyString& name);
|
||||
|
||||
void gather_roots(Badge<Heap>, HashTable<Cell*>&);
|
||||
|
||||
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType);
|
||||
|
|
|
@ -42,6 +42,15 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
enum LocalVariableTag { LocalVariable };
|
||||
Reference(LocalVariableTag, const String& name, bool strict = false)
|
||||
: m_base(js_null())
|
||||
, m_name(name)
|
||||
, m_strict(strict)
|
||||
, m_local_variable(true)
|
||||
{
|
||||
}
|
||||
|
||||
Value base() const { return m_base; }
|
||||
const PropertyName& name() const { return m_name; }
|
||||
bool is_strict() const { return m_strict; }
|
||||
|
@ -57,10 +66,16 @@ public:
|
|||
return m_base.is_boolean() || m_base.is_string() || m_base.is_number();
|
||||
}
|
||||
|
||||
bool is_local_variable() const
|
||||
{
|
||||
return m_local_variable;
|
||||
}
|
||||
|
||||
private:
|
||||
Value m_base { js_undefined() };
|
||||
PropertyName m_name;
|
||||
bool m_strict { false };
|
||||
bool m_local_variable { false };
|
||||
};
|
||||
|
||||
const LogStream& operator<<(const LogStream&, const Value&);
|
||||
|
|
16
Libraries/LibJS/Tests/delete-global-variable.js
Normal file
16
Libraries/LibJS/Tests/delete-global-variable.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
a = 1;
|
||||
assert(delete a === true);
|
||||
|
||||
assertThrowsError(() => {
|
||||
a;
|
||||
}, {
|
||||
error: ReferenceError
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
Loading…
Add table
Reference in a new issue