LibJS: Implement basic object property assignment
This is pretty naive, we just walk up the prototype chain and call any NativeProperty setter that we find. If we don't find one, we put/set the value as an own property of the object itself.
This commit is contained in:
parent
7268499c76
commit
1a10470c1d
Notes:
sideshowbarker
2024-07-19 08:13:59 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/1a10470c1d6
3 changed files with 32 additions and 9 deletions
|
@ -24,6 +24,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/AST.h>
|
||||
|
@ -476,31 +477,42 @@ void Identifier::dump(int indent) const
|
|||
|
||||
Value AssignmentExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
ASSERT(m_lhs->is_identifier());
|
||||
auto name = static_cast<const Identifier&>(*m_lhs).string();
|
||||
AK::Function<void(Value)> commit;
|
||||
if (m_lhs->is_identifier()) {
|
||||
commit = [&](Value value) {
|
||||
auto name = static_cast<const Identifier&>(*m_lhs).string();
|
||||
interpreter.set_variable(name, value);
|
||||
};
|
||||
} else if (m_lhs->is_member_expression()) {
|
||||
commit = [&](Value value) {
|
||||
auto object = static_cast<const MemberExpression&>(*m_lhs).object().execute(interpreter).to_object(interpreter.heap());
|
||||
ASSERT(object.is_object());
|
||||
auto property_name = static_cast<const Identifier&>(static_cast<const MemberExpression&>(*m_lhs).property()).string();
|
||||
object.as_object()->put(property_name, value);
|
||||
};
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto rhs_result = m_rhs->execute(interpreter);
|
||||
|
||||
switch (m_op) {
|
||||
case AssignmentOp::Assignment:
|
||||
interpreter.set_variable(name, rhs_result);
|
||||
break;
|
||||
case AssignmentOp::AdditionAssignment:
|
||||
rhs_result = add(m_lhs->execute(interpreter), rhs_result);
|
||||
interpreter.set_variable(name, rhs_result);
|
||||
break;
|
||||
case AssignmentOp::SubtractionAssignment:
|
||||
rhs_result = sub(m_lhs->execute(interpreter), rhs_result);
|
||||
interpreter.set_variable(name, rhs_result);
|
||||
break;
|
||||
case AssignmentOp::MultiplicationAssignment:
|
||||
rhs_result = mul(m_lhs->execute(interpreter), rhs_result);
|
||||
interpreter.set_variable(name, rhs_result);
|
||||
break;
|
||||
case AssignmentOp::DivisionAssignment:
|
||||
rhs_result = div(m_lhs->execute(interpreter), rhs_result);
|
||||
interpreter.set_variable(name, rhs_result);
|
||||
break;
|
||||
}
|
||||
commit(rhs_result);
|
||||
return rhs_result;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
virtual Value execute(Interpreter&) const = 0;
|
||||
virtual void dump(int indent) const;
|
||||
virtual bool is_identifier() const { return false; }
|
||||
virtual bool is_member_expression() const { return false; }
|
||||
|
||||
protected:
|
||||
ASTNode() {}
|
||||
|
@ -124,8 +125,6 @@ private:
|
|||
};
|
||||
|
||||
class Expression : public ASTNode {
|
||||
public:
|
||||
virtual bool is_member_expression() const { return false; }
|
||||
};
|
||||
|
||||
class FunctionNode {
|
||||
|
@ -594,6 +593,7 @@ public:
|
|||
virtual void dump(int indent) const override;
|
||||
|
||||
const Expression& object() const { return *m_object; }
|
||||
const Expression& property() const { return *m_property; }
|
||||
|
||||
private:
|
||||
virtual bool is_member_expression() const override { return true; }
|
||||
|
|
|
@ -60,6 +60,17 @@ Value Object::get(String property_name) const
|
|||
|
||||
void Object::put(String property_name, Value value)
|
||||
{
|
||||
Object* object = this;
|
||||
while (object) {
|
||||
auto value_here = object->m_properties.get(property_name);
|
||||
if (value_here.has_value()) {
|
||||
if (value_here.value().is_object() && value_here.value().as_object()->is_native_property()) {
|
||||
static_cast<NativeProperty*>(value_here.value().as_object())->set(const_cast<Object*>(this), value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
object = object->prototype();
|
||||
}
|
||||
m_properties.set(property_name, move(value));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue