diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index be00893918..e52f7f00ad 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -855,13 +855,17 @@ void MemberExpression::dump(int indent) const m_property->dump(indent + 1); } -FlyString MemberExpression::computed_property_name(Interpreter& interpreter) const +PropertyName MemberExpression::computed_property_name(Interpreter& interpreter) const { if (!is_computed()) { ASSERT(m_property->is_identifier()); - return static_cast(*m_property).string(); + return PropertyName(static_cast(*m_property).string()); } - return m_property->execute(interpreter).to_string(); + auto index = m_property->execute(interpreter); + // FIXME: What about non-integer numbers tho. + if (index.is_number()) + return PropertyName(index.to_i32()); + return PropertyName(index.to_string()); } Value MemberExpression::execute(Interpreter& interpreter) const diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 3c0d761127..2770d9af77 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace JS { @@ -672,7 +673,7 @@ public: const Expression& object() const { return *m_object; } const Expression& property() const { return *m_property; } - FlyString computed_property_name(Interpreter&) const; + PropertyName computed_property_name(Interpreter&) const; private: virtual bool is_member_expression() const override { return true; } diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 9751ddc0fd..e0bbbe3190 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -150,6 +150,13 @@ Optional Object::get(const FlyString& property_name) const return {}; } +Optional Object::get(PropertyName property_name) const +{ + if (property_name.is_number()) + return get_by_index(property_name.as_number()); + return get(property_name.as_string()); +} + void Object::put_by_index(i32 property_index, Value value) { if (property_index < 0) @@ -189,6 +196,13 @@ void Object::put(const FlyString& property_name, Value value) put_own_property(*this, property_name, value); } +void Object::put(PropertyName property_name, Value value) +{ + if (property_name.is_number()) + return put_by_index(property_name.as_number(), value); + return put(property_name.as_string(), value); +} + void Object::put_native_function(const FlyString& property_name, AK::Function native_function, i32 length) { auto* function = heap().allocate(move(native_function)); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 529fdb92cc..8772e6b1e2 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace JS { @@ -45,9 +46,11 @@ public: Optional get_by_index(i32 property_index) const; Optional get(const FlyString& property_name) const; + Optional get(PropertyName) const; void put_by_index(i32 property_index, Value); void put(const FlyString& property_name, Value); + void put(PropertyName, Value); virtual Optional get_own_property(const Object& this_object, const FlyString& property_name) const; virtual bool put_own_property(Object& this_object, const FlyString& property_name, Value); diff --git a/Libraries/LibJS/Runtime/PropertyName.h b/Libraries/LibJS/Runtime/PropertyName.h new file mode 100644 index 0000000000..6965cb5bdf --- /dev/null +++ b/Libraries/LibJS/Runtime/PropertyName.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace JS { + +class PropertyName { +public: + enum class Type { + Number, + String, + }; + + explicit PropertyName(i32 index) + : m_type(Type::Number) + , m_number(index) + { + ASSERT(m_number >= 0); + } + + explicit PropertyName(const FlyString& string) + : m_type(Type::String) + , m_string(string) + { + } + + bool is_number() const { return m_type == Type::Number; } + bool is_string() const { return m_type == Type::String; } + + i32 as_number() const { return m_number; } + const FlyString& as_string() const { return m_string; } + +private: + Type m_type; + FlyString m_string; + i32 m_number { 0 }; +}; + +}