1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:27:35 +00:00

Libraries: Move to Userland/Libraries/

This commit is contained in:
Andreas Kling 2021-01-12 12:17:30 +01:00
parent dc28c07fa5
commit 13d7c09125
1857 changed files with 266 additions and 274 deletions

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
class Accessor final : public Cell {
public:
static Accessor* create(VM& vm, Function* getter, Function* setter)
{
return vm.heap().allocate_without_global_object<Accessor>(getter, setter);
}
Accessor(Function* getter, Function* setter)
: m_getter(getter)
, m_setter(setter)
{
}
Function* getter() const { return m_getter; }
void set_getter(Function* getter) { m_getter = getter; }
Function* setter() const { return m_setter; }
void set_setter(Function* setter) { m_setter = setter; }
Value call_getter(Value this_value)
{
if (!m_getter)
return js_undefined();
return vm().call(*m_getter, this_value);
}
void call_setter(Value this_value, Value setter_value)
{
if (!m_setter)
return;
// FIXME: It might be nice if we had a way to communicate to our caller if an exception happened after this.
[[maybe_unused]] auto rc = vm().call(*m_setter, this_value, setter_value);
}
void visit_edges(Cell::Visitor& visitor) override
{
visitor.visit(m_getter);
visitor.visit(m_setter);
}
private:
const char* class_name() const override { return "Accessor"; };
Function* m_getter { nullptr };
Function* m_setter { nullptr };
};
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/ArrayPrototype.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
Array* Array::create(GlobalObject& global_object)
{
return global_object.heap().allocate<Array>(global_object, *global_object.array_prototype());
}
Array::Array(Object& prototype)
: Object(prototype)
{
auto& vm = this->vm();
define_native_property(vm.names.length, length_getter, length_setter, Attribute::Writable);
}
Array::~Array()
{
}
Array* Array::typed_this(VM& vm, GlobalObject& global_object)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_array()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "Array");
return nullptr;
}
return static_cast<Array*>(this_object);
}
JS_DEFINE_NATIVE_GETTER(Array::length_getter)
{
auto* array = typed_this(vm, global_object);
if (!array)
return {};
return Value(static_cast<i32>(array->indexed_properties().array_like_size()));
}
JS_DEFINE_NATIVE_SETTER(Array::length_setter)
{
auto* array = typed_this(vm, global_object);
if (!array)
return;
auto length = value.to_number(global_object);
if (vm.exception())
return;
if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "array");
return;
}
array->indexed_properties().set_array_like_size(length.as_double());
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class Array final : public Object {
JS_OBJECT(Array, Object);
public:
static Array* create(GlobalObject&);
explicit Array(Object& prototype);
virtual ~Array() override;
static Array* typed_this(VM&, GlobalObject&);
private:
virtual bool is_array() const override { return true; }
JS_DECLARE_NATIVE_GETTER(length_getter);
JS_DECLARE_NATIVE_SETTER(length_setter);
};
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
ArrayBuffer* ArrayBuffer::create(GlobalObject& global_object, size_t byte_size)
{
return global_object.heap().allocate<ArrayBuffer>(global_object, byte_size, *global_object.array_buffer_prototype());
}
ArrayBuffer::ArrayBuffer(size_t byte_size, Object& prototype)
: Object(prototype)
, m_buffer(ByteBuffer::create_zeroed(byte_size))
{
}
ArrayBuffer::~ArrayBuffer()
{
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <AK/ByteBuffer.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class ArrayBuffer : public Object {
JS_OBJECT(ArrayBuffer, Object);
public:
static ArrayBuffer* create(GlobalObject&, size_t);
ArrayBuffer(size_t, Object& prototype);
virtual ~ArrayBuffer() override;
size_t byte_length() const { return m_buffer.size(); }
ByteBuffer& buffer() { return m_buffer; }
const ByteBuffer& buffer() const { return m_buffer; }
private:
ByteBuffer m_buffer;
};
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/ArrayBufferConstructor.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/TypedArray.h>
namespace JS {
ArrayBufferConstructor::ArrayBufferConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.ArrayBuffer, *global_object.function_prototype())
{
}
void ArrayBufferConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_property(vm.names.prototype, global_object.array_buffer_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
define_native_function(vm.names.isView, is_view, 1, attr);
}
ArrayBufferConstructor::~ArrayBufferConstructor()
{
}
Value ArrayBufferConstructor::call()
{
auto& vm = this->vm();
vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, vm.names.ArrayBuffer);
return {};
}
Value ArrayBufferConstructor::construct(Function&)
{
auto& vm = this->vm();
auto byte_length = vm.argument(0).to_index(global_object());
if (vm.exception()) {
// Re-throw more specific RangeError
vm.clear_exception();
vm.throw_exception<RangeError>(global_object(), ErrorType::InvalidLength, "array buffer");
return {};
}
return ArrayBuffer::create(global_object(), byte_length);
}
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferConstructor::is_view)
{
auto arg = vm.argument(0);
if (!arg.is_object())
return Value(false);
if (arg.as_object().is_typed_array())
return Value(true);
// FIXME: Check for DataView as well
return Value(false);
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class ArrayBufferConstructor final : public NativeFunction {
JS_OBJECT(ArrayBufferConstructor, NativeFunction);
public:
explicit ArrayBufferConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ArrayBufferConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(is_view);
};
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/ArrayBuffer.h>
#include <LibJS/Runtime/ArrayBufferPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
ArrayBufferPrototype::ArrayBufferPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void ArrayBufferPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.slice, slice, 2, attr);
// FIXME: This should be an accessor property
define_native_property(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "ArrayBuffer"), Attribute::Configurable);
}
ArrayBufferPrototype::~ArrayBufferPrototype()
{
}
static ArrayBuffer* array_buffer_object_from(VM& vm, GlobalObject& global_object)
{
// ArrayBuffer.prototype.* deliberately don't coerce |this| value to object.
auto this_value = vm.this_value(global_object);
if (!this_value.is_object())
return nullptr;
auto& this_object = this_value.as_object();
if (!is<ArrayBuffer>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "ArrayBuffer");
return nullptr;
}
return static_cast<ArrayBuffer*>(&this_object);
}
JS_DEFINE_NATIVE_FUNCTION(ArrayBufferPrototype::slice)
{
auto array_buffer_object = array_buffer_object_from(vm, global_object);
if (!array_buffer_object)
return {};
TODO();
}
JS_DEFINE_NATIVE_GETTER(ArrayBufferPrototype::byte_length_getter)
{
auto array_buffer_object = array_buffer_object_from(vm, global_object);
if (!array_buffer_object)
return {};
// FIXME: Check for shared buffer
// FIXME: Check for detached buffer
return Value((double)array_buffer_object->byte_length());
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ArrayBufferPrototype final : public Object {
JS_OBJECT(ArrayBufferPrototype, Object);
public:
explicit ArrayBufferPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ArrayBufferPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(slice);
JS_DECLARE_NATIVE_GETTER(byte_length_getter);
};
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/ArrayConstructor.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
#include <LibJS/Runtime/Shape.h>
namespace JS {
ArrayConstructor::ArrayConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Array, *global_object.function_prototype())
{
}
ArrayConstructor::~ArrayConstructor()
{
}
void ArrayConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.array_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.from, from, 1, attr);
define_native_function(vm.names.isArray, is_array, 1, attr);
define_native_function(vm.names.of, of, 0, attr);
}
Value ArrayConstructor::call()
{
if (vm().argument_count() <= 0)
return Array::create(global_object());
if (vm().argument_count() == 1 && vm().argument(0).is_number()) {
auto array_length_value = vm().argument(0);
if (!array_length_value.is_integer() || array_length_value.as_i32() < 0) {
vm().throw_exception<RangeError>(global_object(), ErrorType::InvalidLength, "array");
return {};
}
auto* array = Array::create(global_object());
array->indexed_properties().set_array_like_size(array_length_value.as_i32());
return array;
}
auto* array = Array::create(global_object());
for (size_t i = 0; i < vm().argument_count(); ++i)
array->indexed_properties().append(vm().argument(i));
return array;
}
Value ArrayConstructor::construct(Function&)
{
return call();
}
JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from)
{
auto value = vm.argument(0);
auto object = value.to_object(global_object);
if (!object)
return {};
auto* array = Array::create(global_object);
// Array.from() lets you create Arrays from:
if (auto size = object->indexed_properties().array_like_size()) {
// * array-like objects (objects with a length property and indexed elements)
MarkedValueList elements(vm.heap());
elements.ensure_capacity(size);
for (size_t i = 0; i < size; ++i) {
elements.append(object->get(i));
if (vm.exception())
return {};
}
array->set_indexed_property_elements(move(elements));
} else {
// * iterable objects
get_iterator_values(global_object, value, [&](Value element) {
if (vm.exception())
return IterationDecision::Break;
array->indexed_properties().append(element);
return IterationDecision::Continue;
});
if (vm.exception())
return {};
}
// FIXME: if interpreter.argument_count() >= 2: mapFn
// FIXME: if interpreter.argument_count() >= 3: thisArg
return array;
}
JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::is_array)
{
auto value = vm.argument(0);
return Value(value.is_array());
}
JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::of)
{
auto* array = Array::create(global_object);
for (size_t i = 0; i < vm.argument_count(); ++i)
array->indexed_properties().append(vm.argument(i));
return array;
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class ArrayConstructor final : public NativeFunction {
JS_OBJECT(ArrayConstructor, NativeFunction);
public:
explicit ArrayConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ArrayConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(from);
JS_DECLARE_NATIVE_FUNCTION(is_array);
JS_DECLARE_NATIVE_FUNCTION(of);
};
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/ArrayIterator.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
ArrayIterator* ArrayIterator::create(GlobalObject& global_object, Value array, Object::PropertyKind iteration_kind)
{
return global_object.heap().allocate<ArrayIterator>(global_object, *global_object.array_iterator_prototype(), array, iteration_kind);
}
ArrayIterator::ArrayIterator(Object& prototype, Value array, Object::PropertyKind iteration_kind)
: Object(prototype)
, m_array(array)
, m_iteration_kind(iteration_kind)
{
}
ArrayIterator::~ArrayIterator()
{
}
void ArrayIterator::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_array);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ArrayIterator final : public Object {
JS_OBJECT(ArrayIterator, Object);
public:
static ArrayIterator* create(GlobalObject&, Value array, Object::PropertyKind iteration_kind);
explicit ArrayIterator(Object& prototype, Value array, Object::PropertyKind iteration_kind);
virtual ~ArrayIterator() override;
Value array() const { return m_array; }
Object::PropertyKind iteration_kind() const { return m_iteration_kind; }
size_t index() const { return m_index; }
private:
friend class ArrayIteratorPrototype;
virtual void visit_edges(Cell::Visitor&) override;
Value m_array;
Object::PropertyKind m_iteration_kind;
size_t m_index { 0 };
};
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/ArrayIterator.h>
#include <LibJS/Runtime/ArrayIteratorPrototype.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
namespace JS {
ArrayIteratorPrototype::ArrayIteratorPrototype(GlobalObject& global_object)
: Object(*global_object.iterator_prototype())
{
}
void ArrayIteratorPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_native_function(vm.names.next, next, 0, Attribute::Configurable | Attribute::Writable);
define_property(global_object.vm().well_known_symbol_to_string_tag(), js_string(global_object.heap(), "Array Iterator"), Attribute::Configurable);
}
ArrayIteratorPrototype::~ArrayIteratorPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(ArrayIteratorPrototype::next)
{
auto this_value = vm.this_value(global_object);
if (!this_value.is_object() || !is<ArrayIterator>(this_value.as_object())) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "Array Iterator");
return {};
}
auto& this_object = this_value.as_object();
auto& iterator = static_cast<ArrayIterator&>(this_object);
auto target_array = iterator.array();
if (target_array.is_undefined())
return create_iterator_result_object(global_object, js_undefined(), true);
ASSERT(target_array.is_object());
auto& array = target_array.as_object();
auto index = iterator.index();
auto iteration_kind = iterator.iteration_kind();
// FIXME: Typed array check
auto length = array.indexed_properties().array_like_size();
if (index >= length) {
iterator.m_array = js_undefined();
return create_iterator_result_object(global_object, js_undefined(), true);
}
iterator.m_index++;
if (iteration_kind == Object::PropertyKind::Key)
return create_iterator_result_object(global_object, Value(static_cast<i32>(index)), false);
auto value = array.get(index);
if (vm.exception())
return {};
if (iteration_kind == Object::PropertyKind::Value)
return create_iterator_result_object(global_object, value, false);
auto* entry_array = Array::create(global_object);
entry_array->define_property(0, Value(static_cast<i32>(index)));
entry_array->define_property(1, value);
return create_iterator_result_object(global_object, entry_array, false);
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ArrayIteratorPrototype final : public Object {
JS_OBJECT(ArrayIteratorPrototype, Object)
public:
ArrayIteratorPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ArrayIteratorPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(next);
};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ArrayPrototype final : public Object {
JS_OBJECT(ArrayPrototype, Object);
public:
ArrayPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ArrayPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(filter);
JS_DECLARE_NATIVE_FUNCTION(for_each);
JS_DECLARE_NATIVE_FUNCTION(map);
JS_DECLARE_NATIVE_FUNCTION(pop);
JS_DECLARE_NATIVE_FUNCTION(push);
JS_DECLARE_NATIVE_FUNCTION(shift);
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_FUNCTION(to_locale_string);
JS_DECLARE_NATIVE_FUNCTION(unshift);
JS_DECLARE_NATIVE_FUNCTION(join);
JS_DECLARE_NATIVE_FUNCTION(concat);
JS_DECLARE_NATIVE_FUNCTION(slice);
JS_DECLARE_NATIVE_FUNCTION(index_of);
JS_DECLARE_NATIVE_FUNCTION(reduce);
JS_DECLARE_NATIVE_FUNCTION(reduce_right);
JS_DECLARE_NATIVE_FUNCTION(reverse);
JS_DECLARE_NATIVE_FUNCTION(sort);
JS_DECLARE_NATIVE_FUNCTION(last_index_of);
JS_DECLARE_NATIVE_FUNCTION(includes);
JS_DECLARE_NATIVE_FUNCTION(find);
JS_DECLARE_NATIVE_FUNCTION(find_index);
JS_DECLARE_NATIVE_FUNCTION(some);
JS_DECLARE_NATIVE_FUNCTION(every);
JS_DECLARE_NATIVE_FUNCTION(splice);
JS_DECLARE_NATIVE_FUNCTION(fill);
JS_DECLARE_NATIVE_FUNCTION(values);
};
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/BigInt.h>
namespace JS {
BigInt::BigInt(Crypto::SignedBigInteger big_integer)
: m_big_integer(move(big_integer))
{
ASSERT(!m_big_integer.is_invalid());
}
BigInt::~BigInt()
{
}
BigInt* js_bigint(Heap& heap, Crypto::SignedBigInteger big_integer)
{
return heap.allocate_without_global_object<BigInt>(move(big_integer));
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Runtime/Cell.h>
namespace JS {
class BigInt final : public Cell {
public:
BigInt(Crypto::SignedBigInteger);
virtual ~BigInt();
const Crypto::SignedBigInteger& big_integer() const { return m_big_integer; }
const String to_string() const { return String::formatted("{}n", m_big_integer.to_base10()); }
private:
virtual const char* class_name() const override { return "BigInt"; }
Crypto::SignedBigInteger m_big_integer;
};
BigInt* js_bigint(Heap&, Crypto::SignedBigInteger);
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/String.h>
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Runtime/BigIntConstructor.h>
#include <LibJS/Runtime/BigIntObject.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
BigIntConstructor::BigIntConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.BigInt, *global_object.function_prototype())
{
}
void BigIntConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.bigint_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.asIntN, as_int_n, 2, attr);
define_native_function(vm.names.asUintN, as_uint_n, 2, attr);
}
BigIntConstructor::~BigIntConstructor()
{
}
Value BigIntConstructor::call()
{
auto primitive = vm().argument(0).to_primitive(Value::PreferredType::Number);
if (vm().exception())
return {};
if (primitive.is_number()) {
if (!primitive.is_integer()) {
vm().throw_exception<RangeError>(global_object(), ErrorType::BigIntIntArgument);
return {};
}
return js_bigint(heap(), Crypto::SignedBigInteger { primitive.as_i32() });
}
auto* bigint = vm().argument(0).to_bigint(global_object());
if (vm().exception())
return {};
return bigint;
}
Value BigIntConstructor::construct(Function&)
{
vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, "BigInt");
return {};
}
JS_DEFINE_NATIVE_FUNCTION(BigIntConstructor::as_int_n)
{
TODO();
}
JS_DEFINE_NATIVE_FUNCTION(BigIntConstructor::as_uint_n)
{
TODO();
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class BigIntConstructor final : public NativeFunction {
JS_OBJECT(BigIntConstructor, NativeFunction);
public:
explicit BigIntConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~BigIntConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(as_int_n);
JS_DECLARE_NATIVE_FUNCTION(as_uint_n);
};
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/BigIntObject.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BigIntObject* BigIntObject::create(GlobalObject& global_object, BigInt& bigint)
{
return global_object.heap().allocate<BigIntObject>(global_object, bigint, *global_object.bigint_prototype());
}
BigIntObject::BigIntObject(BigInt& bigint, Object& prototype)
: Object(prototype)
, m_bigint(bigint)
{
}
BigIntObject::~BigIntObject()
{
}
void BigIntObject::visit_edges(Cell::Visitor& visitor)
{
Object::visit_edges(visitor);
visitor.visit(&m_bigint);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/BigInt.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class BigIntObject final : public Object {
JS_OBJECT(BigIntObject, Object);
public:
static BigIntObject* create(GlobalObject&, BigInt&);
BigIntObject(BigInt&, Object& prototype);
virtual ~BigIntObject();
const BigInt& bigint() const { return m_bigint; }
virtual Value value_of() const override
{
return Value(&m_bigint);
}
private:
virtual void visit_edges(Visitor&) override;
BigInt& m_bigint;
};
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/BigIntObject.h>
#include <LibJS/Runtime/BigIntPrototype.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BigIntPrototype::BigIntPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void BigIntPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.valueOf, value_of, 0, attr);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
}
BigIntPrototype::~BigIntPrototype()
{
}
static BigIntObject* bigint_object_from(VM& vm, GlobalObject& global_object)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return nullptr;
if (!is<BigIntObject>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "BigInt");
return nullptr;
}
return static_cast<BigIntObject*>(this_object);
}
JS_DEFINE_NATIVE_FUNCTION(BigIntPrototype::to_string)
{
auto* bigint_object = bigint_object_from(vm, global_object);
if (!bigint_object)
return {};
return js_string(vm, bigint_object->bigint().big_integer().to_base10());
}
JS_DEFINE_NATIVE_FUNCTION(BigIntPrototype::to_locale_string)
{
return to_string(vm, global_object);
}
JS_DEFINE_NATIVE_FUNCTION(BigIntPrototype::value_of)
{
auto* bigint_object = bigint_object_from(vm, global_object);
if (!bigint_object)
return {};
return bigint_object->value_of();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class BigIntPrototype final : public Object {
JS_OBJECT(BigIntPrototype, Object);
public:
explicit BigIntPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~BigIntPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_FUNCTION(to_locale_string);
JS_DECLARE_NATIVE_FUNCTION(value_of);
};
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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.
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/BooleanConstructor.h>
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/BooleanPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BooleanConstructor::BooleanConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Boolean, *global_object.function_prototype())
{
}
void BooleanConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, Value(global_object.boolean_prototype()), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
BooleanConstructor::~BooleanConstructor()
{
}
Value BooleanConstructor::call()
{
return Value(vm().argument(0).to_boolean());
}
Value BooleanConstructor::construct(Function&)
{
return BooleanObject::create(global_object(), vm().argument(0).to_boolean());
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class BooleanConstructor final : public NativeFunction {
JS_OBJECT(BooleanConstructor, NativeFunction);
public:
explicit BooleanConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~BooleanConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
};
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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.
*/
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BooleanObject* BooleanObject::create(GlobalObject& global_object, bool value)
{
return global_object.heap().allocate<BooleanObject>(global_object, value, *global_object.boolean_prototype());
}
BooleanObject::BooleanObject(bool value, Object& prototype)
: Object(prototype)
, m_value(value)
{
}
BooleanObject::~BooleanObject()
{
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class BooleanObject : public Object {
JS_OBJECT(BooleanObject, Object);
public:
static BooleanObject* create(GlobalObject&, bool);
BooleanObject(bool, Object& prototype);
virtual ~BooleanObject() override;
virtual Value value_of() const override
{
return Value(m_value);
}
private:
bool m_value { false };
};
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/BooleanPrototype.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BooleanPrototype::BooleanPrototype(GlobalObject& global_object)
: BooleanObject(false, *global_object.object_prototype())
{
}
void BooleanPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
BooleanObject::initialize(global_object);
define_native_function(vm.names.toString, to_string, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.valueOf, value_of, 0, Attribute::Writable | Attribute::Configurable);
}
BooleanPrototype::~BooleanPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(BooleanPrototype::to_string)
{
auto this_value = vm.this_value(global_object);
if (this_value.is_boolean())
return js_string(vm, this_value.as_bool() ? "true" : "false");
if (!this_value.is_object() || !is<BooleanObject>(this_value.as_object())) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Boolean");
return {};
}
bool bool_value = static_cast<const BooleanObject&>(this_value.as_object()).value_of().as_bool();
return js_string(vm, bool_value ? "true" : "false");
}
JS_DEFINE_NATIVE_FUNCTION(BooleanPrototype::value_of)
{
auto this_value = vm.this_value(global_object);
if (this_value.is_boolean())
return this_value;
if (!this_value.is_object() || !is<BooleanObject>(this_value.as_object())) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Boolean");
return {};
}
return static_cast<const BooleanObject&>(this_value.as_object()).value_of();
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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 <LibJS/Runtime/BooleanObject.h>
namespace JS {
class BooleanPrototype final : public BooleanObject {
JS_OBJECT(BooleanPrototype, BooleanObject);
public:
explicit BooleanPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~BooleanPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_FUNCTION(value_of);
};
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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.
*/
#include <LibJS/Runtime/BoundFunction.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
BoundFunction::BoundFunction(GlobalObject& global_object, Function& target_function, Value bound_this, Vector<Value> arguments, i32 length, Object* constructor_prototype)
: Function::Function(*global_object.function_prototype(), bound_this, move(arguments))
, m_target_function(&target_function)
, m_constructor_prototype(constructor_prototype)
, m_name(String::formatted("bound {}", target_function.name()))
, m_length(length)
{
}
void BoundFunction::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Function::initialize(global_object);
define_property(vm.names.length, Value(m_length), Attribute::Configurable);
}
BoundFunction::~BoundFunction()
{
}
Value BoundFunction::call()
{
return m_target_function->call();
}
Value BoundFunction::construct(Function& new_target)
{
if (auto this_value = vm().this_value(global_object()); m_constructor_prototype && this_value.is_object()) {
this_value.as_object().set_prototype(m_constructor_prototype);
if (vm().exception())
return {};
}
return m_target_function->construct(new_target);
}
LexicalEnvironment* BoundFunction::create_environment()
{
return m_target_function->create_environment();
}
void BoundFunction::visit_edges(Visitor& visitor)
{
Function::visit_edges(visitor);
visitor.visit(m_target_function);
visitor.visit(m_constructor_prototype);
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020, Jack Karamanian <karamanian.jack@gmail.com>
* 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 <LibJS/Runtime/Function.h>
namespace JS {
class BoundFunction final : public Function {
JS_OBJECT(BoundFunction, Function);
public:
BoundFunction(GlobalObject&, Function& target_function, Value bound_this, Vector<Value> arguments, i32 length, Object* constructor_prototype);
virtual void initialize(GlobalObject&) override;
virtual ~BoundFunction();
virtual Value call() override;
virtual Value construct(Function& new_target) override;
virtual LexicalEnvironment* create_environment() override;
virtual void visit_edges(Visitor&) override;
virtual const FlyString& name() const override
{
return m_name;
}
Function& target_function() const
{
return *m_target_function;
}
virtual bool is_strict_mode() const override { return m_target_function->is_strict_mode(); }
private:
Function* m_target_function = nullptr;
Object* m_constructor_prototype = nullptr;
FlyString m_name;
i32 m_length { 0 };
};
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Heap/HeapBlock.h>
#include <LibJS/Runtime/Cell.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
void Cell::Visitor::visit(Cell* cell)
{
if (cell)
visit_impl(cell);
}
void Cell::Visitor::visit(Value value)
{
if (value.is_cell())
visit_impl(value.as_cell());
}
Heap& Cell::heap() const
{
return HeapBlock::from_cell(this)->heap();
}
VM& Cell::vm() const
{
return heap().vm();
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/Format.h>
#include <AK/Forward.h>
#include <AK/Noncopyable.h>
#include <AK/String.h>
#include <AK/TypeCasts.h>
#include <LibJS/Forward.h>
namespace JS {
class Cell {
AK_MAKE_NONCOPYABLE(Cell);
AK_MAKE_NONMOVABLE(Cell);
public:
virtual void initialize(GlobalObject&) { }
virtual ~Cell() { }
bool is_marked() const { return m_mark; }
void set_marked(bool b) { m_mark = b; }
bool is_live() const { return m_live; }
void set_live(bool b) { m_live = b; }
virtual const char* class_name() const = 0;
class Visitor {
public:
void visit(Cell*);
void visit(Value);
protected:
virtual void visit_impl(Cell*) = 0;
};
virtual void visit_edges(Visitor&) { }
Heap& heap() const;
VM& vm() const;
protected:
Cell() { }
private:
bool m_mark { false };
bool m_live { true };
};
}
template<>
struct AK::Formatter<JS::Cell> : AK::Formatter<FormatString> {
void format(FormatBuilder& builder, const JS::Cell* cell)
{
if (!cell)
Formatter<FormatString>::format(builder, "Cell{nullptr}");
else
Formatter<FormatString>::format(builder, "{}({})", cell->class_name(), cell);
}
};

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/FlyString.h>
#include <LibJS/Forward.h>
namespace JS {
#define ENUMERATE_STANDARD_PROPERTY_NAMES(P) \
P(BYTES_PER_ELEMENT) \
P(BigInt) \
P(Boolean) \
P(E) \
P(EPSILON) \
P(Infinity) \
P(JSON) \
P(LN10) \
P(LN2) \
P(LOG10E) \
P(LOG2E) \
P(MAX_SAFE_INTEGER) \
P(MIN_SAFE_INTEGER) \
P(Math) \
P(NEGATIVE_INFINITY) \
P(NaN) \
P(Number) \
P(PI) \
P(POSITIVE_INFINITY) \
P(Proxy) \
P(Reflect) \
P(RegExp) \
P(SQRT1_2) \
P(SQRT2) \
P(String) \
P(Symbol) \
P(UTC) \
P(abs) \
P(acos) \
P(acosh) \
P(apply) \
P(arguments) \
P(asIntN) \
P(asUintN) \
P(asin) \
P(asinh) \
P(atan) \
P(atan2) \
P(atanh) \
P(bind) \
P(byteLength) \
P(call) \
P(cbrt) \
P(ceil) \
P(charAt) \
P(charCodeAt) \
P(clear) \
P(clz32) \
P(concat) \
P(configurable) \
P(console) \
P(construct) \
P(constructor) \
P(cos) \
P(cosh) \
P(count) \
P(countReset) \
P(debug) \
P(defineProperty) \
P(deleteProperty) \
P(description) \
P(done) \
P(dotAll) \
P(endsWith) \
P(entries) \
P(enumerable) \
P(error) \
P(every) \
P(exec) \
P(exp) \
P(expm1) \
P(fill) \
P(filter) \
P(find) \
P(findIndex) \
P(flags) \
P(floor) \
P(forEach) \
P(from) \
P(fromCharCode) \
P(fround) \
P(gc) \
P(get) \
P(getDate) \
P(getDay) \
P(getFullYear) \
P(getHours) \
P(getMilliseconds) \
P(getMinutes) \
P(getMonth) \
P(getOwnPropertyDescriptor) \
P(getOwnPropertyNames) \
P(getPrototypeOf) \
P(getSeconds) \
P(getTime) \
P(getUTCDate) \
P(getUTCDay) \
P(getUTCFullYear) \
P(getUTCHours) \
P(getUTCMilliseconds) \
P(getUTCMinutes) \
P(getUTCMonth) \
P(getUTCSeconds) \
P(global) \
P(globalThis) \
P(groups) \
P(has) \
P(hasOwnProperty) \
P(hypot) \
P(ignoreCase) \
P(imul) \
P(includes) \
P(index) \
P(indexOf) \
P(info) \
P(input) \
P(is) \
P(isArray) \
P(isExtensible) \
P(isFinite) \
P(isInteger) \
P(isNaN) \
P(isPrototypeOf) \
P(isSafeInteger) \
P(isView) \
P(join) \
P(keyFor) \
P(keys) \
P(lastIndex) \
P(lastIndexOf) \
P(length) \
P(log) \
P(log1p) \
P(log2) \
P(log10) \
P(map) \
P(max) \
P(message) \
P(min) \
P(multiline) \
P(name) \
P(next) \
P(now) \
P(of) \
P(ownKeys) \
P(padEnd) \
P(padStart) \
P(parse) \
P(parseFloat) \
P(parseInt) \
P(pop) \
P(pow) \
P(preventExtensions) \
P(propertyIsEnumerable) \
P(prototype) \
P(push) \
P(random) \
P(raw) \
P(reduce) \
P(reduceRight) \
P(repeat) \
P(reverse) \
P(round) \
P(set) \
P(setPrototypeOf) \
P(shift) \
P(sign) \
P(sin) \
P(sinh) \
P(slice) \
P(some) \
P(sort) \
P(source) \
P(splice) \
P(sqrt) \
P(startsWith) \
P(sticky) \
P(stringify) \
P(substr) \
P(substring) \
P(tan) \
P(tanh) \
P(test) \
P(toDateString) \
P(toISOString) \
P(toJSON) \
P(toLocaleDateString) \
P(toLocaleString) \
P(toLocaleTimeString) \
P(toLowerCase) \
P(toString) \
P(toTimeString) \
P(toUpperCase) \
P(trace) \
P(trim) \
P(trimEnd) \
P(trimStart) \
P(trunc) \
P(undefined) \
P(unicode) \
P(unshift) \
P(value) \
P(valueOf) \
P(values) \
P(warn) \
P(writable)
struct CommonPropertyNames {
FlyString for_ { "for" };
#define __ENUMERATE(x) FlyString x { #x };
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
#undef __ENUMERATE
#define __JS_ENUMERATE(x, a, b, c, t) FlyString x { #x };
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(x, a) FlyString x { #x };
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
#undef __JS_ENUMERATE
};
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* Copyright (c) 2020, Emanuele Torre <torreemanuele6@gmail.com>
* 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.
*/
#include <AK/FlyString.h>
#include <AK/Function.h>
#include <LibJS/Console.h>
#include <LibJS/Runtime/ConsoleObject.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
ConsoleObject::ConsoleObject(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void ConsoleObject::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
define_native_function(vm.names.log, log);
define_native_function(vm.names.debug, debug);
define_native_function(vm.names.info, info);
define_native_function(vm.names.warn, warn);
define_native_function(vm.names.error, error);
define_native_function(vm.names.trace, trace);
define_native_function(vm.names.count, count);
define_native_function(vm.names.countReset, count_reset);
define_native_function(vm.names.clear, clear);
}
ConsoleObject::~ConsoleObject()
{
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::log)
{
return global_object.console().log();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::debug)
{
return global_object.console().debug();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::info)
{
return global_object.console().info();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::warn)
{
return global_object.console().warn();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::error)
{
return global_object.console().error();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::trace)
{
return global_object.console().trace();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::count)
{
return global_object.console().count();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::count_reset)
{
return global_object.console().count_reset();
}
JS_DEFINE_NATIVE_FUNCTION(ConsoleObject::clear)
{
return global_object.console().clear();
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ConsoleObject final : public Object {
JS_OBJECT(ConsoleObject, Object);
public:
explicit ConsoleObject(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ConsoleObject() override;
private:
JS_DECLARE_NATIVE_FUNCTION(log);
JS_DECLARE_NATIVE_FUNCTION(debug);
JS_DECLARE_NATIVE_FUNCTION(info);
JS_DECLARE_NATIVE_FUNCTION(warn);
JS_DECLARE_NATIVE_FUNCTION(error);
JS_DECLARE_NATIVE_FUNCTION(trace);
JS_DECLARE_NATIVE_FUNCTION(count);
JS_DECLARE_NATIVE_FUNCTION(count_reset);
JS_DECLARE_NATIVE_FUNCTION(clear);
};
}

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/StringBuilder.h>
#include <LibCore/DateTime.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
Date* Date::create(GlobalObject& global_object, Core::DateTime datetime, u16 milliseconds)
{
return global_object.heap().allocate<Date>(global_object, datetime, milliseconds, *global_object.date_prototype());
}
Date::Date(Core::DateTime datetime, u16 milliseconds, Object& prototype)
: Object(prototype)
, m_datetime(datetime)
, m_milliseconds(milliseconds)
{
}
Date::~Date()
{
}
tm Date::to_utc_tm() const
{
time_t timestamp = m_datetime.timestamp();
struct tm tm;
gmtime_r(&timestamp, &tm);
return tm;
}
int Date::utc_date() const
{
return to_utc_tm().tm_mday;
}
int Date::utc_day() const
{
return to_utc_tm().tm_wday;
}
int Date::utc_full_year() const
{
return to_utc_tm().tm_year + 1900;
}
int Date::utc_hours() const
{
return to_utc_tm().tm_hour;
}
int Date::utc_minutes() const
{
return to_utc_tm().tm_min;
}
int Date::utc_month() const
{
return to_utc_tm().tm_mon;
}
int Date::utc_seconds() const
{
return to_utc_tm().tm_sec;
}
String Date::iso_date_string() const
{
auto tm = to_utc_tm();
int year = tm.tm_year + 1900;
int month = tm.tm_mon + 1;
StringBuilder builder;
if (year < 0)
builder.appendf("-%06d", -year);
else if (year > 9999)
builder.appendf("+%06d", year);
else
builder.appendf("%04d", year);
builder.append('-');
builder.appendf("%02d", month);
builder.append('-');
builder.appendf("%02d", tm.tm_mday);
builder.append('T');
builder.appendf("%02d", tm.tm_hour);
builder.append(':');
builder.appendf("%02d", tm.tm_min);
builder.append(':');
builder.appendf("%02d", tm.tm_sec);
builder.append('.');
builder.appendf("%03d", m_milliseconds);
builder.append('Z');
return builder.build();
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibCore/DateTime.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class Date final : public Object {
JS_OBJECT(Date, Object);
public:
static Date* create(GlobalObject&, Core::DateTime, u16 milliseconds);
Date(Core::DateTime datetime, u16 milliseconds, Object& prototype);
virtual ~Date() override;
Core::DateTime& datetime() { return m_datetime; }
const Core::DateTime& datetime() const { return m_datetime; }
int date() const { return datetime().day(); }
int day() const { return datetime().weekday(); }
int full_year() const { return datetime().year(); }
int hours() const { return datetime().hour(); }
u16 milliseconds() const { return m_milliseconds; }
int minutes() const { return datetime().minute(); }
int month() const { return datetime().month() - 1; }
int seconds() const { return datetime().second(); }
double time() const { return datetime().timestamp() * 1000.0 + milliseconds(); }
int year() const { return datetime().day(); }
int utc_date() const;
int utc_day() const;
int utc_full_year() const;
int utc_hours() const;
int utc_milliseconds() const { return milliseconds(); }
int utc_minutes() const;
int utc_month() const;
int utc_seconds() const;
String date_string() const { return m_datetime.to_string("%a %b %d %Y"); }
// FIXME: Deal with timezones once SerenityOS has a working tzset(3)
String time_string() const { return m_datetime.to_string("%T GMT+0000 (UTC)"); }
String string() const
{
return String::formatted("{} {}", date_string(), time_string());
}
String iso_date_string() const;
// FIXME: One day, implement real locale support. Until then, everyone gets what the Clock MenuApplet displays.
String locale_date_string() const { return m_datetime.to_string("%Y-%m-%d"); }
String locale_string() const { return m_datetime.to_string(); }
String locale_time_string() const { return m_datetime.to_string("%H:%M:%S"); }
virtual Value value_of() const override
{
return Value(static_cast<double>(m_datetime.timestamp() * 1000 + m_milliseconds));
}
private:
tm to_utc_tm() const;
Core::DateTime m_datetime;
u16 m_milliseconds;
};
}

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* Copyright (c) 2020, Nico Weber <thakis@chromium.org>
* 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.
*/
#include <AK/GenericLexer.h>
#include <LibCore/DateTime.h>
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/DateConstructor.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/VM.h>
#include <ctype.h>
#include <sys/time.h>
#include <time.h>
namespace JS {
static Value parse_simplified_iso8601(const String& iso_8601)
{
// Date.parse() is allowed to accept many formats. We strictly only accept things matching
// http://www.ecma-international.org/ecma-262/#sec-date-time-string-format
GenericLexer lexer(iso_8601);
auto lex_n_digits = [&](size_t n, int& out) {
if (lexer.tell_remaining() < n)
return false;
int r = 0;
for (size_t i = 0; i < n; ++i) {
char ch = lexer.consume();
if (!isdigit(ch))
return false;
r = 10 * r + ch - '0';
}
out = r;
return true;
};
int year = -1, month = -1, day = -1;
int hours = -1, minutes = -1, seconds = -1, milliseconds = -1;
char timezone = -1;
int timezone_hours = -1, timezone_minutes = -1;
auto lex_year = [&]() {
if (lexer.consume_specific('+'))
return lex_n_digits(6, year);
if (lexer.consume_specific('-')) {
int absolute_year;
if (!lex_n_digits(6, absolute_year))
return false;
year = -absolute_year;
return true;
}
return lex_n_digits(4, year);
};
auto lex_month = [&]() { return lex_n_digits(2, month) && month >= 1 && month <= 12; };
auto lex_day = [&]() { return lex_n_digits(2, day) && day >= 1 && day <= 31; };
auto lex_date = [&]() { return lex_year() && (!lexer.consume_specific('-') || (lex_month() && (!lexer.consume_specific('-') || lex_day()))); };
auto lex_hours_minutes = [&](int& out_h, int& out_m) {
int h, m;
if (lex_n_digits(2, h) && h >= 0 && h <= 24 && lexer.consume_specific(':') && lex_n_digits(2, m) && m >= 0 && m <= 59) {
out_h = h;
out_m = m;
return true;
}
return false;
};
auto lex_seconds = [&]() { return lex_n_digits(2, seconds) && seconds >= 0 && seconds <= 59; };
auto lex_milliseconds = [&]() { return lex_n_digits(3, milliseconds); };
auto lex_seconds_milliseconds = [&]() { return lex_seconds() && (!lexer.consume_specific('.') || lex_milliseconds()); };
auto lex_timezone = [&]() {
if (lexer.consume_specific('+')) {
timezone = '+';
return lex_hours_minutes(timezone_hours, timezone_minutes);
}
if (lexer.consume_specific('-')) {
timezone = '-';
return lex_hours_minutes(timezone_hours, timezone_minutes);
}
if (lexer.consume_specific('Z'))
timezone = 'Z';
return true;
};
auto lex_time = [&]() { return lex_hours_minutes(hours, minutes) && (!lexer.consume_specific(':') || lex_seconds_milliseconds()) && lex_timezone(); };
if (!lex_date() || (lexer.consume_specific('T') && !lex_time()) || !lexer.is_eof()) {
return js_nan();
}
// We parsed a valid date simplified ISO 8601 string. Values not present in the string are -1.
ASSERT(year != -1); // A valid date string always has at least a year.
struct tm tm = {};
tm.tm_year = year - 1900;
tm.tm_mon = month == -1 ? 0 : month - 1;
tm.tm_mday = day == -1 ? 1 : day;
tm.tm_hour = hours == -1 ? 0 : hours;
tm.tm_min = minutes == -1 ? 0 : minutes;
tm.tm_sec = seconds == -1 ? 0 : seconds;
// http://www.ecma-international.org/ecma-262/#sec-date.parse:
// "When the UTC offset representation is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time."
time_t timestamp;
if (timezone != -1 || hours == -1)
timestamp = timegm(&tm);
else
timestamp = mktime(&tm);
if (timezone == '-')
timestamp += (timezone_hours * 60 + timezone_minutes) * 60;
else if (timezone == '+')
timestamp -= (timezone_hours * 60 + timezone_minutes) * 60;
// FIXME: reject timestamp if resulting value wouldn't fit in a double
if (milliseconds == -1)
milliseconds = 0;
return Value(1000.0 * timestamp + milliseconds);
}
DateConstructor::DateConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Date, *global_object.function_prototype())
{
}
void DateConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.date_prototype(), 0);
define_property(vm.names.length, Value(7), Attribute::Configurable);
define_native_function(vm.names.now, now, 0, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.parse, parse, 1, Attribute::Writable | Attribute::Configurable);
define_native_function(vm.names.UTC, utc, 1, Attribute::Writable | Attribute::Configurable);
}
DateConstructor::~DateConstructor()
{
}
Value DateConstructor::call()
{
auto date = construct(*this);
if (!date.is_object())
return {};
return js_string(heap(), static_cast<Date&>(date.as_object()).string());
}
Value DateConstructor::construct(Function&)
{
if (vm().argument_count() == 0) {
struct timeval tv;
gettimeofday(&tv, nullptr);
auto datetime = Core::DateTime::now();
auto milliseconds = static_cast<u16>(tv.tv_usec / 1000);
return Date::create(global_object(), datetime, milliseconds);
}
if (vm().argument_count() == 1) {
auto value = vm().argument(0);
if (value.is_string())
value = parse_simplified_iso8601(value.as_string().string());
// A timestamp since the epoch, in UTC.
// FIXME: Date() probably should use a double as internal representation, so that NaN arguments and larger offsets are handled correctly.
double value_as_double = value.to_double(global_object());
auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value_as_double / 1000));
auto milliseconds = static_cast<u16>(fmod(value_as_double, 1000));
return Date::create(global_object(), datetime, milliseconds);
}
// A date/time in components, in local time.
// FIXME: This doesn't construct an "Invalid Date" object if one of the parameters is NaN.
auto arg_or = [this](size_t i, i32 fallback) { return vm().argument_count() > i ? vm().argument(i).to_i32(global_object()) : fallback; };
int year = vm().argument(0).to_i32(global_object());
int month_index = vm().argument(1).to_i32(global_object());
int day = arg_or(2, 1);
int hours = arg_or(3, 0);
int minutes = arg_or(4, 0);
int seconds = arg_or(5, 0);
int milliseconds = arg_or(6, 0);
seconds += milliseconds / 1000;
milliseconds %= 1000;
if (milliseconds < 0) {
seconds -= 1;
milliseconds += 1000;
}
if (year >= 0 && year <= 99)
year += 1900;
int month = month_index + 1;
auto datetime = Core::DateTime::create(year, month, day, hours, minutes, seconds);
return Date::create(global_object(), datetime, milliseconds);
}
JS_DEFINE_NATIVE_FUNCTION(DateConstructor::now)
{
struct timeval tv;
gettimeofday(&tv, nullptr);
return Value(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0);
}
JS_DEFINE_NATIVE_FUNCTION(DateConstructor::parse)
{
if (!vm.argument_count())
return js_nan();
auto iso_8601 = vm.argument(0).to_string(global_object);
if (vm.exception())
return js_nan();
return parse_simplified_iso8601(iso_8601);
}
JS_DEFINE_NATIVE_FUNCTION(DateConstructor::utc)
{
auto arg_or = [&vm, &global_object](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_i32(global_object) : fallback; };
int year = vm.argument(0).to_i32(global_object);
if (year >= 0 && year <= 99)
year += 1900;
struct tm tm = {};
tm.tm_year = year - 1900;
tm.tm_mon = arg_or(1, 0); // 0-based in both tm and JavaScript
tm.tm_mday = arg_or(2, 1);
tm.tm_hour = arg_or(3, 0);
tm.tm_min = arg_or(4, 0);
tm.tm_sec = arg_or(5, 0);
// timegm() doesn't read tm.tm_wday and tm.tm_yday, no need to fill them in.
int milliseconds = arg_or(6, 0);
return Value(1000.0 * timegm(&tm) + milliseconds);
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class DateConstructor final : public NativeFunction {
JS_OBJECT(DateConstructor, NativeFunction);
public:
explicit DateConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~DateConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(now);
JS_DECLARE_NATIVE_FUNCTION(parse);
JS_DECLARE_NATIVE_FUNCTION(utc);
};
}

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Function.h>
#include <AK/String.h>
#include <LibCore/DateTime.h>
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/DatePrototype.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
static Date* typed_this(VM& vm, GlobalObject& global_object)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return nullptr;
if (!is<Date>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Date");
return nullptr;
}
return static_cast<Date*>(this_object);
}
DatePrototype::DatePrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void DatePrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.getDate, get_date, 0, attr);
define_native_function(vm.names.getDay, get_day, 0, attr);
define_native_function(vm.names.getFullYear, get_full_year, 0, attr);
define_native_function(vm.names.getHours, get_hours, 0, attr);
define_native_function(vm.names.getMilliseconds, get_milliseconds, 0, attr);
define_native_function(vm.names.getMinutes, get_minutes, 0, attr);
define_native_function(vm.names.getMonth, get_month, 0, attr);
define_native_function(vm.names.getSeconds, get_seconds, 0, attr);
define_native_function(vm.names.getTime, get_time, 0, attr);
define_native_function(vm.names.getUTCDate, get_utc_date, 0, attr);
define_native_function(vm.names.getUTCDay, get_utc_day, 0, attr);
define_native_function(vm.names.getUTCFullYear, get_utc_full_year, 0, attr);
define_native_function(vm.names.getUTCHours, get_utc_hours, 0, attr);
define_native_function(vm.names.getUTCMilliseconds, get_utc_milliseconds, 0, attr);
define_native_function(vm.names.getUTCMinutes, get_utc_minutes, 0, attr);
define_native_function(vm.names.getUTCMonth, get_utc_month, 0, attr);
define_native_function(vm.names.getUTCSeconds, get_utc_seconds, 0, attr);
define_native_function(vm.names.toDateString, to_date_string, 0, attr);
define_native_function(vm.names.toISOString, to_iso_string, 0, attr);
define_native_function(vm.names.toLocaleDateString, to_locale_date_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.toLocaleTimeString, to_locale_time_string, 0, attr);
define_native_function(vm.names.toTimeString, to_time_string, 0, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
// Aliases.
define_native_function(vm.names.valueOf, get_time, 0, attr);
// toJSON() isn't quite an alias for toISOString():
// - it returns null instead of throwing RangeError
// - its .length is 1, not 0
// - it can be transferred to other prototypes
}
DatePrototype::~DatePrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_date)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->date()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_day)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->day()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_full_year)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->full_year()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_hours)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->hours()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_milliseconds)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->milliseconds()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_minutes)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->minutes()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_month)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->month()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_seconds)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->seconds()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_time)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(this_object->time());
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_date)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_date()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_day)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_day()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_full_year)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_full_year()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_hours)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_hours()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_milliseconds)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_milliseconds()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_month)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_month()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_minutes)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_minutes()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_seconds)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
return Value(static_cast<double>(this_object->utc_seconds()));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_date_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
auto string = this_object->date_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_iso_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
auto string = this_object->iso_date_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_date_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
// FIXME: Optional locales, options params.
auto string = this_object->locale_date_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
// FIXME: Optional locales, options params.
auto string = this_object->locale_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_time_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
// FIXME: Optional locales, options params.
auto string = this_object->locale_time_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_time_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
auto string = this_object->time_string();
return js_string(vm, move(string));
}
JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_string)
{
auto* this_object = typed_this(vm, global_object);
if (!this_object)
return {};
auto string = this_object->string();
return js_string(vm, move(string));
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class DatePrototype final : public Object {
JS_OBJECT(DatePrototype, Object);
public:
explicit DatePrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~DatePrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(get_date);
JS_DECLARE_NATIVE_FUNCTION(get_day);
JS_DECLARE_NATIVE_FUNCTION(get_full_year);
JS_DECLARE_NATIVE_FUNCTION(get_hours);
JS_DECLARE_NATIVE_FUNCTION(get_milliseconds);
JS_DECLARE_NATIVE_FUNCTION(get_minutes);
JS_DECLARE_NATIVE_FUNCTION(get_month);
JS_DECLARE_NATIVE_FUNCTION(get_seconds);
JS_DECLARE_NATIVE_FUNCTION(get_time);
JS_DECLARE_NATIVE_FUNCTION(get_utc_date);
JS_DECLARE_NATIVE_FUNCTION(get_utc_day);
JS_DECLARE_NATIVE_FUNCTION(get_utc_full_year);
JS_DECLARE_NATIVE_FUNCTION(get_utc_hours);
JS_DECLARE_NATIVE_FUNCTION(get_utc_milliseconds);
JS_DECLARE_NATIVE_FUNCTION(get_utc_minutes);
JS_DECLARE_NATIVE_FUNCTION(get_utc_month);
JS_DECLARE_NATIVE_FUNCTION(get_utc_seconds);
JS_DECLARE_NATIVE_FUNCTION(to_date_string);
JS_DECLARE_NATIVE_FUNCTION(to_iso_string);
JS_DECLARE_NATIVE_FUNCTION(to_locale_date_string);
JS_DECLARE_NATIVE_FUNCTION(to_locale_string);
JS_DECLARE_NATIVE_FUNCTION(to_locale_time_string);
JS_DECLARE_NATIVE_FUNCTION(to_time_string);
JS_DECLARE_NATIVE_FUNCTION(to_string);
};
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
Error* Error::create(GlobalObject& global_object, const FlyString& name, const String& message)
{
return global_object.heap().allocate<Error>(global_object, name, message, *global_object.error_prototype());
}
Error::Error(const FlyString& name, const String& message, Object& prototype)
: Object(prototype)
, m_name(name)
, m_message(message)
{
}
Error::~Error()
{
}
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ClassName* ClassName::create(GlobalObject& global_object, const String& message) \
{ \
return global_object.heap().allocate<ClassName>(global_object, message, *global_object.snake_name##_prototype()); \
} \
ClassName::ClassName(const String& message, Object& prototype) \
: Error(vm().names.ClassName, message, prototype) \
{ \
} \
ClassName::~ClassName() { }
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/FlyString.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class Error : public Object {
JS_OBJECT(Error, Object);
public:
static Error* create(GlobalObject&, const FlyString& name, const String& message);
Error(const FlyString& name, const String& message, Object& prototype);
virtual ~Error() override;
const FlyString& name() const { return m_name; }
const String& message() const { return m_message; }
void set_name(const FlyString& name) { m_name = name; }
private:
FlyString m_name;
String m_message;
};
#define DECLARE_ERROR_SUBCLASS(ClassName, snake_name, PrototypeName, ConstructorName) \
class ClassName final : public Error { \
JS_OBJECT(ClassName, Error); \
\
public: \
static ClassName* create(GlobalObject&, const String& message); \
\
ClassName(const String& message, Object& prototype); \
virtual ~ClassName() override; \
};
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
DECLARE_ERROR_SUBCLASS(ClassName, snake_name, PrototypeName, ConstructorName)
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/ErrorConstructor.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
ErrorConstructor::ErrorConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Error, *global_object.function_prototype())
{
}
void ErrorConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.error_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
ErrorConstructor::~ErrorConstructor()
{
}
Value ErrorConstructor::call()
{
return construct(*this);
}
Value ErrorConstructor::construct(Function&)
{
auto& vm = this->vm();
String message = "";
if (!vm.call_frame().arguments.is_empty() && !vm.call_frame().arguments[0].is_undefined()) {
message = vm.call_frame().arguments[0].to_string(global_object());
if (vm.exception())
return {};
}
return Error::create(global_object(), vm.names.Error, message);
}
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ConstructorName::ConstructorName(GlobalObject& global_object) \
: NativeFunction(*global_object.function_prototype()) \
{ \
} \
void ConstructorName::initialize(GlobalObject& global_object) \
{ \
auto& vm = this->vm(); \
NativeFunction::initialize(global_object); \
define_property(vm.names.prototype, global_object.snake_name##_prototype(), 0); \
define_property(vm.names.length, Value(1), Attribute::Configurable); \
} \
ConstructorName::~ConstructorName() { } \
Value ConstructorName::call() \
{ \
return construct(*this); \
} \
Value ConstructorName::construct(Function&) \
{ \
String message = ""; \
if (!vm().call_frame().arguments.is_empty() && !vm().call_frame().arguments[0].is_undefined()) { \
message = vm().call_frame().arguments[0].to_string(global_object()); \
if (vm().exception()) \
return {}; \
} \
return ClassName::create(global_object(), message); \
}
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/NativeFunction.h>
namespace JS {
class ErrorConstructor final : public NativeFunction {
JS_OBJECT(ErrorConstructor, NativeFunction);
public:
explicit ErrorConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ErrorConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
};
#define DECLARE_ERROR_SUBCLASS_CONSTRUCTOR(ClassName, snake_name, PrototypeName, ConstructorName) \
class ConstructorName final : public NativeFunction { \
JS_OBJECT(ConstructorName, NativeFunction); \
\
public: \
explicit ConstructorName(GlobalObject&); \
virtual void initialize(GlobalObject&) override; \
virtual ~ConstructorName() override; \
virtual Value call() override; \
virtual Value construct(Function& new_target) override; \
\
private: \
virtual bool has_constructor() const override { return true; } \
};
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
DECLARE_ERROR_SUBCLASS_CONSTRUCTOR(ClassName, snake_name, PrototypeName, ConstructorName)
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/ErrorPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
ErrorPrototype::ErrorPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void ErrorPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_property(vm.names.name, name_getter, name_setter, attr);
define_native_property(vm.names.message, message_getter, {}, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
}
ErrorPrototype::~ErrorPrototype()
{
}
JS_DEFINE_NATIVE_GETTER(ErrorPrototype::name_getter)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!is<Error>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
return {};
}
return js_string(vm, static_cast<const Error*>(this_object)->name());
}
JS_DEFINE_NATIVE_SETTER(ErrorPrototype::name_setter)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return;
if (!is<Error>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
return;
}
auto name = value.to_string(global_object);
if (vm.exception())
return;
static_cast<Error*>(this_object)->set_name(name);
}
JS_DEFINE_NATIVE_GETTER(ErrorPrototype::message_getter)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!is<Error>(this_object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAn, "Error");
return {};
}
return js_string(vm, static_cast<const Error*>(this_object)->message());
}
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
{
if (!vm.this_value(global_object).is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, vm.this_value(global_object).to_string_without_side_effects());
return {};
}
auto& this_object = vm.this_value(global_object).as_object();
String name = "Error";
auto name_property = this_object.get(vm.names.name);
if (vm.exception())
return {};
if (!name_property.is_empty() && !name_property.is_undefined()) {
name = name_property.to_string(global_object);
if (vm.exception())
return {};
}
String message = "";
auto message_property = this_object.get(vm.names.message);
if (vm.exception())
return {};
if (!message_property.is_empty() && !message_property.is_undefined()) {
message = message_property.to_string(global_object);
if (vm.exception())
return {};
}
if (name.length() == 0)
return js_string(vm, message);
if (message.length() == 0)
return js_string(vm, name);
return js_string(vm, String::formatted("{}: {}", name, message));
}
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
PrototypeName::PrototypeName(GlobalObject& global_object) \
: Object(*global_object.error_prototype()) \
{ \
} \
PrototypeName::~PrototypeName() { }
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Error.h>
namespace JS {
class ErrorPrototype final : public Object {
JS_OBJECT(ErrorPrototype, Object);
public:
explicit ErrorPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ErrorPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_GETTER(name_getter);
JS_DECLARE_NATIVE_SETTER(name_setter);
JS_DECLARE_NATIVE_GETTER(message_getter);
};
#define DECLARE_ERROR_SUBCLASS_PROTOTYPE(ClassName, snake_name, PrototypeName, ConstructorName) \
class PrototypeName final : public Object { \
JS_OBJECT(PrototypeName, Object); \
\
public: \
explicit PrototypeName(GlobalObject&); \
virtual void initialize(GlobalObject&) override { } \
virtual ~PrototypeName() override; \
};
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
DECLARE_ERROR_SUBCLASS_PROTOTYPE(ClassName, snake_name, PrototypeName, ConstructorName)
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/ErrorTypes.h>
namespace JS {
#define __ENUMERATE_JS_ERROR(name, message) \
const ErrorType ErrorType::name = ErrorType(message);
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
#undef __ENUMERATE_JS_ERROR
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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
#define JS_ENUMERATE_ERROR_TYPES(M) \
M(ArrayMaxSize, "Maximum array size exceeded") \
M(ArrayPrototypeOneArg, "Array.prototype.{}() requires at least one argument") \
M(AccessorBadField, "Accessor descriptor's '{}' field must be a function or undefined") \
M(AccessorValueOrWritable, "Accessor property descriptor cannot specify a value or writable key") \
M(BigIntBadOperator, "Cannot use {} operator with BigInt") \
M(BigIntBadOperatorOtherType, "Cannot use {} operator with BigInt and other type") \
M(BigIntIntArgument, "BigInt argument must be an integer") \
M(BigIntInvalidValue, "Invalid value for BigInt: {}") \
M(ClassConstructorWithoutNew, "Class constructor {} must be called with 'new'") \
M(ClassIsAbstract, "Abstract class {} cannot be constructed directly") \
M(ClassDoesNotExtendAConstructorOrNull, "Class extends value {} is not a constructor or null") \
M(ConstructorWithoutNew, "{} constructor must be called with 'new'") \
M(Convert, "Cannot convert {} to {}") \
M(ConvertUndefinedToObject, "Cannot convert undefined to object") \
M(DescChangeNonConfigurable, "Cannot change attributes of non-configurable property '{}'") \
M(FunctionArgsNotObject, "Argument array must be an object") \
M(InOperatorWithObject, "'in' operator must be used on an object") \
M(InstanceOfOperatorBadPrototype, "'prototype' property of {} is not an object") \
M(InvalidAssignToConst, "Invalid assignment to const variable") \
M(InvalidIndex, "Index must be a positive integer") \
M(InvalidLeftHandAssignment, "Invalid left-hand side in assignment") \
M(InvalidLength, "Invalid {} length") \
M(InvalidRadix, "Radix must be an integer no less than 2, and no greater than 36") \
M(IsNotA, "{} is not a {}") \
M(IsNotAEvaluatedFrom, "{} is not a {} (evaluated from '{}')") \
M(IterableNextBadReturn, "iterator.next() returned a non-object value") \
M(IterableNextNotAFunction, "'next' property on returned object from Symbol.iterator method is " \
"not a function") \
M(JsonBigInt, "Cannot serialize BigInt value to JSON") \
M(JsonCircular, "Cannot stringify circular object") \
M(JsonMalformed, "Malformed JSON string") \
M(NotA, "Not a {} object") \
M(NotAConstructor, "{} is not a constructor") \
M(NotAFunction, "{} is not a function") \
M(NotAFunctionNoParam, "Not a function") \
M(NotAn, "Not an {} object") \
M(NotAnObject, "{} is not an object") \
M(NotASymbol, "{} is not a symbol") \
M(NotIterable, "{} is not iterable") \
M(NonExtensibleDefine, "Cannot define property {} on non-extensible object") \
M(NumberIncompatibleThis, "Number.prototype.{} method called with incompatible this target") \
M(ObjectDefinePropertyReturnedFalse, "Object's [[DefineProperty]] method returned false") \
M(ObjectSetPrototypeOfReturnedFalse, "Object's [[SetPrototypeOf]] method returned false") \
M(ObjectSetPrototypeOfTwoArgs, "Object.setPrototypeOf requires at least two arguments") \
M(ObjectPreventExtensionsReturnedFalse, "Object's [[PreventExtensions]] method returned false") \
M(ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, \
"Object prototype must not be {} on a super property access") \
M(ObjectPrototypeWrongType, "Prototype must be an object or null") \
M(ProxyConstructBadReturnType, "Proxy handler's construct trap violates invariant: must return " \
"an object") \
M(ProxyConstructorBadType, "Expected {} argument of Proxy constructor to be object, got {}") \
M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates " \
"invariant: a property cannot be defined as non-configurable if it already exists on the " \
"target object as a configurable property") \
M(ProxyDefinePropIncompatibleDescriptor, "Proxy handler's defineProperty trap violates " \
"invariant: the new descriptor is not compatible with the existing descriptor of the " \
"property on the target") \
M(ProxyDefinePropNonConfigurableNonExisting, "Proxy handler's defineProperty trap " \
"violates invariant: a property cannot be defined as non-configurable if it does not " \
"already exist on the target object") \
M(ProxyDefinePropNonExtensible, "Proxy handler's defineProperty trap violates invariant: " \
"a property cannot be reported as being defined if the property does not exist on " \
"the target and the target is non-extensible") \
M(ProxyDeleteNonConfigurable, "Proxy handler's deleteProperty trap violates invariant: " \
"cannot report a non-configurable own property of the target as deleted") \
M(ProxyGetImmutableDataProperty, "Proxy handler's get trap violates invariant: the " \
"returned value must match the value on the target if the property exists on the " \
"target as a non-writable, non-configurable own data property") \
M(ProxyGetNonConfigurableAccessor, "Proxy handler's get trap violates invariant: the " \
"returned value must be undefined if the property exists on the target as a " \
"non-configurable accessor property with an undefined get attribute") \
M(ProxyGetOwnDescriptorExistingConfigurable, "Proxy handler's getOwnPropertyDescriptor " \
"trap violates invariant: a property cannot be defined as non-configurable if it " \
"already exists on the target object as a configurable property") \
M(ProxyGetOwnDescriptorInvalidDescriptor, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: invalid property descriptor for existing property on the target") \
M(ProxyGetOwnDescriptorInvalidNonConfig, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot report target's property as non-configurable if the " \
"property does not exist, or if it is configurable") \
M(ProxyGetOwnDescriptorNonConfigurable, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot return undefined for a property on the target which is " \
"a non-configurable property") \
M(ProxyGetOwnDescriptorReturn, "Proxy handler's getOwnPropertyDescriptor trap violates " \
"invariant: must return an object or undefined") \
M(ProxyGetOwnDescriptorUndefReturn, "Proxy handler's getOwnPropertyDescriptor trap " \
"violates invariant: cannot report a property as being undefined if it exists as an " \
"own property of the target and the target is non-extensible") \
M(ProxyGetPrototypeOfNonExtensible, "Proxy handler's getPrototypeOf trap violates " \
"invariant: cannot return a different prototype object for a non-extensible target") \
M(ProxyGetPrototypeOfReturn, "Proxy handler's getPrototypeOf trap violates invariant: " \
"must return an object or null") \
M(ProxyHasExistingNonConfigurable, "Proxy handler's has trap violates invariant: a " \
"property cannot be reported as non-existent if it exists on the target as a " \
"non-configurable property") \
M(ProxyHasExistingNonExtensible, "Proxy handler's has trap violates invariant: a property " \
"cannot be reported as non-existent if it exists on the target and the target is " \
"non-extensible") \
M(ProxyInvalidTrap, "Proxy handler's {} trap wasn't undefined, null, or callable") \
M(ProxyIsExtensibleReturn, "Proxy handler's isExtensible trap violates invariant: " \
"return value must match the target's extensibility") \
M(ProxyPreventExtensionsReturn, "Proxy handler's preventExtensions trap violates " \
"invariant: cannot return true if the target object is extensible") \
M(ProxyRevoked, "An operation was performed on a revoked Proxy object") \
M(ProxySetImmutableDataProperty, "Proxy handler's set trap violates invariant: cannot " \
"return true for a property on the target which is a non-configurable, non-writable " \
"own data property") \
M(ProxySetNonConfigurableAccessor, "Proxy handler's set trap violates invariant: cannot " \
"return true for a property on the target which is a non-configurable own accessor " \
"property with an undefined set attribute") \
M(ProxySetPrototypeOfNonExtensible, "Proxy handler's setPrototypeOf trap violates " \
"invariant: the argument must match the prototype of the target if the " \
"target is non-extensible") \
M(ProxyTwoArguments, "Proxy constructor requires at least two arguments") \
M(ReduceNoInitial, "Reduce of empty array with no initial value") \
M(ReferencePrimitiveAssignment, "Cannot assign property {} to primitive value") \
M(ReferenceUnresolvable, "Unresolvable reference") \
M(ReflectArgumentMustBeAFunction, "First argument of Reflect.{}() must be a function") \
M(ReflectArgumentMustBeAnObject, "First argument of Reflect.{}() must be an object") \
M(ReflectBadArgumentsList, "Arguments list must be an object") \
M(ReflectBadNewTarget, "Optional third argument of Reflect.construct() must be a constructor") \
M(ReflectBadDescriptorArgument, "Descriptor argument is not an object") \
M(RegExpCompileError, "RegExp compile error: {}") \
M(RegExpObjectBadFlag, "Invalid RegExp flag '{}'") \
M(RegExpObjectRepeatedFlag, "Repeated RegExp flag '{}'") \
M(StringRawCannotConvert, "Cannot convert property 'raw' to object from {}") \
M(StringRepeatCountMustBe, "repeat count must be a {} number") \
M(ThisHasNotBeenInitialized, "|this| has not been initialized") \
M(ThisIsAlreadyInitialized, "|this| is already initialized") \
M(ToObjectNullOrUndef, "ToObject on null or undefined") \
M(TypedArrayInvalidBufferLength, "Invalid buffer length for {}: must be a multiple of {}, got {}") \
M(TypedArrayInvalidByteOffset, "Invalid byte offset for {}: must be a multiple of {}, got {}") \
M(TypedArrayOutOfRangeByteOffset, "Typed array byte offset {} is out of range for buffer with length {}") \
M(TypedArrayOutOfRangeByteOffsetOrLength, "Typed array range {}:{} is out of range for buffer with length {}") \
M(UnknownIdentifier, "'{}' is not defined") \
/* LibWeb bindings */ \
M(NotAByteString, "Argument to {}() must be a byte string") \
M(BadArgCountOne, "{}() needs one argument") \
M(BadArgCountAtLeastOne, "{}() needs at least one argument") \
M(BadArgCountMany, "{}() needs {} arguments")
namespace JS {
class ErrorType {
public:
#define __ENUMERATE_JS_ERROR(name, message) \
static const ErrorType name;
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
#undef __ENUMERATE_JS_ERROR
const char* message() const
{
return m_message;
}
private:
explicit ErrorType(const char* message)
: m_message(message)
{
}
const char* m_message;
};
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/String.h>
#include <LibJS/AST.h>
#include <LibJS/Runtime/Exception.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
Exception::Exception(Value value)
: m_value(value)
{
auto& call_stack = vm().call_stack();
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
String function_name = call_stack[i]->function_name;
if (function_name.is_empty())
function_name = "<anonymous>";
m_trace.append(function_name);
}
auto& node_stack = vm().node_stack();
for (ssize_t i = node_stack.size() - 1; i >= 0; --i) {
auto* node = node_stack[i];
ASSERT(node);
m_source_ranges.append(node->source_range());
}
}
Exception::~Exception()
{
}
void Exception::visit_edges(Visitor& visitor)
{
Cell::visit_edges(visitor);
visitor.visit(m_value);
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/Vector.h>
#include <LibJS/Runtime/Cell.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/SourceRange.h>
namespace JS {
class Exception : public Cell {
public:
explicit Exception(Value);
virtual ~Exception() override;
Value value() const { return m_value; }
const Vector<String>& trace() const { return m_trace; }
const Vector<SourceRange>& source_ranges() const { return m_source_ranges; }
private:
virtual const char* class_name() const override { return "Exception"; }
virtual void visit_edges(Visitor&) override;
Value m_value;
Vector<String> m_trace;
Vector<SourceRange> m_source_ranges;
};
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/BoundFunction.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
Function::Function(Object& prototype)
: Function(prototype, {}, {})
{
}
Function::Function(Object& prototype, Value bound_this, Vector<Value> bound_arguments)
: Object(prototype)
, m_bound_this(bound_this)
, m_bound_arguments(move(bound_arguments))
{
}
Function::~Function()
{
}
BoundFunction* Function::bind(Value bound_this_value, Vector<Value> arguments)
{
auto& vm = this->vm();
Function& target_function = is<BoundFunction>(*this) ? static_cast<BoundFunction&>(*this).target_function() : *this;
auto bound_this_object = [&vm, bound_this_value, this]() -> Value {
if (!m_bound_this.is_empty())
return m_bound_this;
switch (bound_this_value.type()) {
case Value::Type::Undefined:
case Value::Type::Null:
if (vm.in_strict_mode())
return bound_this_value;
return &global_object();
default:
return bound_this_value.to_object(global_object());
}
}();
i32 computed_length = 0;
auto length_property = get(vm.names.length);
if (vm.exception())
return nullptr;
if (length_property.is_number())
computed_length = max(0, length_property.as_i32() - static_cast<i32>(arguments.size()));
Object* constructor_prototype = nullptr;
auto prototype_property = target_function.get(vm.names.prototype);
if (vm.exception())
return nullptr;
if (prototype_property.is_object())
constructor_prototype = &prototype_property.as_object();
auto all_bound_arguments = bound_arguments();
all_bound_arguments.append(move(arguments));
return heap().allocate<BoundFunction>(global_object(), global_object(), target_function, bound_this_object, move(all_bound_arguments), computed_length, constructor_prototype);
}
void Function::visit_edges(Visitor& visitor)
{
Object::visit_edges(visitor);
visitor.visit(m_bound_this);
for (auto argument : m_bound_arguments)
visitor.visit(argument);
}
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/String.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class Function : public Object {
JS_OBJECT(Function, Object);
public:
enum class ConstructorKind {
Base,
Derived,
};
virtual ~Function();
virtual void initialize(GlobalObject&) override { }
virtual Value call() = 0;
virtual Value construct(Function& new_target) = 0;
virtual const FlyString& name() const = 0;
virtual LexicalEnvironment* create_environment() = 0;
virtual void visit_edges(Visitor&) override;
BoundFunction* bind(Value bound_this_value, Vector<Value> arguments);
Value bound_this() const { return m_bound_this; }
const Vector<Value>& bound_arguments() const { return m_bound_arguments; }
Value home_object() const { return m_home_object; }
void set_home_object(Value home_object) { m_home_object = home_object; }
ConstructorKind constructor_kind() const { return m_constructor_kind; };
void set_constructor_kind(ConstructorKind constructor_kind) { m_constructor_kind = constructor_kind; }
virtual bool is_strict_mode() const { return false; }
protected:
explicit Function(Object& prototype);
Function(Object& prototype, Value bound_this, Vector<Value> bound_arguments);
private:
virtual bool is_function() const override { return true; }
Value m_bound_this;
Vector<Value> m_bound_arguments;
Value m_home_object;
ConstructorKind m_constructor_kind = ConstructorKind::Base;
};
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/StringBuilder.h>
#include <LibJS/AST.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Parser.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FunctionConstructor.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ScriptFunction.h>
namespace JS {
FunctionConstructor::FunctionConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Function, *global_object.function_prototype())
{
}
void FunctionConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.function_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
}
FunctionConstructor::~FunctionConstructor()
{
}
Value FunctionConstructor::call()
{
return construct(*this);
}
Value FunctionConstructor::construct(Function&)
{
auto& vm = this->vm();
String parameters_source = "";
String body_source = "";
if (vm.argument_count() == 1) {
body_source = vm.argument(0).to_string(global_object());
if (vm.exception())
return {};
}
if (vm.argument_count() > 1) {
Vector<String> parameters;
for (size_t i = 0; i < vm.argument_count() - 1; ++i) {
parameters.append(vm.argument(i).to_string(global_object()));
if (vm.exception())
return {};
}
StringBuilder parameters_builder;
parameters_builder.join(',', parameters);
parameters_source = parameters_builder.build();
body_source = vm.argument(vm.argument_count() - 1).to_string(global_object());
if (vm.exception())
return {};
}
auto source = String::formatted("function anonymous({}\n) {{\n{}\n}}", parameters_source, body_source);
auto parser = Parser(Lexer(source));
auto function_expression = parser.parse_function_node<FunctionExpression>();
if (parser.has_errors()) {
auto error = parser.errors()[0];
vm.throw_exception<SyntaxError>(global_object(), error.to_string());
return {};
}
OwnPtr<Interpreter> local_interpreter;
Interpreter* interpreter = vm.interpreter_if_exists();
if (!interpreter) {
local_interpreter = Interpreter::create_with_existing_global_object(global_object());
interpreter = local_interpreter.ptr();
}
VM::InterpreterExecutionScope scope(*interpreter);
return function_expression->execute(*interpreter, global_object());
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class FunctionConstructor final : public NativeFunction {
JS_OBJECT(FunctionConstructor, NativeFunction);
public:
explicit FunctionConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~FunctionConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
};
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Function.h>
#include <AK/StringBuilder.h>
#include <LibJS/AST.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/BoundFunction.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/FunctionPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/MarkedValueList.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/ScriptFunction.h>
namespace JS {
FunctionPrototype::FunctionPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void FunctionPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.apply, apply, 2, attr);
define_native_function(vm.names.bind, bind, 1, attr);
define_native_function(vm.names.call, call, 1, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.well_known_symbol_has_instance(), symbol_has_instance, 1, 0);
define_property(vm.names.length, Value(0), Attribute::Configurable);
define_property(vm.names.name, js_string(heap(), ""), Attribute::Configurable);
}
FunctionPrototype::~FunctionPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
return {};
}
auto& function = static_cast<Function&>(*this_object);
auto this_arg = vm.argument(0);
auto arg_array = vm.argument(1);
if (arg_array.is_nullish())
return vm.call(function, this_arg);
if (!arg_array.is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::FunctionArgsNotObject);
return {};
}
auto length = length_of_array_like(global_object, arg_array.as_object());
if (vm.exception())
return {};
MarkedValueList arguments(vm.heap());
for (size_t i = 0; i < length; ++i) {
auto element = arg_array.as_object().get(i);
if (vm.exception())
return {};
arguments.append(element.value_or(js_undefined()));
}
return vm.call(function, this_arg, move(arguments));
}
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
return {};
}
auto& this_function = static_cast<Function&>(*this_object);
auto bound_this_arg = vm.argument(0);
Vector<Value> arguments;
if (vm.argument_count() > 1) {
arguments = vm.call_frame().arguments;
arguments.remove(0);
}
return this_function.bind(bound_this_arg, move(arguments));
}
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::call)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
return {};
}
auto& function = static_cast<Function&>(*this_object);
auto this_arg = vm.argument(0);
MarkedValueList arguments(vm.heap());
if (vm.argument_count() > 1) {
for (size_t i = 1; i < vm.argument_count(); ++i)
arguments.append(vm.argument(i));
}
return vm.call(function, this_arg, move(arguments));
}
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::to_string)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
return {};
}
String function_name = static_cast<Function*>(this_object)->name();
String function_parameters = "";
String function_body;
if (is<NativeFunction>(this_object) || is<BoundFunction>(this_object)) {
function_body = String::formatted(" [{}]", this_object->class_name());
} else {
StringBuilder parameters_builder;
auto first = true;
for (auto& parameter : static_cast<ScriptFunction*>(this_object)->parameters()) {
if (!first)
parameters_builder.append(", ");
first = false;
parameters_builder.append(parameter.name);
if (parameter.default_value) {
// FIXME: See note below
parameters_builder.append(" = TODO");
}
}
function_parameters = parameters_builder.build();
// FIXME: ASTNodes should be able to dump themselves to source strings - something like this:
// auto& body = static_cast<ScriptFunction*>(this_object)->body();
// function_body = body.to_source();
function_body = " ???";
}
auto function_source = String::formatted(
"function {}({}) {{\n{}\n}}",
function_name.is_null() ? "" : function_name, function_parameters, function_body);
return js_string(vm, function_source);
}
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::symbol_has_instance)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
if (!this_object->is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Function");
return {};
}
return ordinary_has_instance(global_object, vm.argument(0), this_object);
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class FunctionPrototype final : public Object {
JS_OBJECT(FunctionPrototype, Object);
public:
explicit FunctionPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~FunctionPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(apply);
JS_DECLARE_NATIVE_FUNCTION(bind);
JS_DECLARE_NATIVE_FUNCTION(call);
JS_DECLARE_NATIVE_FUNCTION(to_string);
JS_DECLARE_NATIVE_FUNCTION(symbol_has_instance);
};
}

View file

@ -0,0 +1,310 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/Utf8View.h>
#include <LibJS/Console.h>
#include <LibJS/Heap/DeferGC.h>
#include <LibJS/Runtime/ArrayBufferConstructor.h>
#include <LibJS/Runtime/ArrayBufferPrototype.h>
#include <LibJS/Runtime/ArrayConstructor.h>
#include <LibJS/Runtime/ArrayIteratorPrototype.h>
#include <LibJS/Runtime/ArrayPrototype.h>
#include <LibJS/Runtime/BigIntConstructor.h>
#include <LibJS/Runtime/BigIntPrototype.h>
#include <LibJS/Runtime/BooleanConstructor.h>
#include <LibJS/Runtime/BooleanPrototype.h>
#include <LibJS/Runtime/ConsoleObject.h>
#include <LibJS/Runtime/DateConstructor.h>
#include <LibJS/Runtime/DatePrototype.h>
#include <LibJS/Runtime/ErrorConstructor.h>
#include <LibJS/Runtime/ErrorPrototype.h>
#include <LibJS/Runtime/FunctionConstructor.h>
#include <LibJS/Runtime/FunctionPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorPrototype.h>
#include <LibJS/Runtime/JSONObject.h>
#include <LibJS/Runtime/MathObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/NumberConstructor.h>
#include <LibJS/Runtime/NumberPrototype.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/ObjectConstructor.h>
#include <LibJS/Runtime/ObjectPrototype.h>
#include <LibJS/Runtime/ProxyConstructor.h>
#include <LibJS/Runtime/ReflectObject.h>
#include <LibJS/Runtime/RegExpConstructor.h>
#include <LibJS/Runtime/RegExpPrototype.h>
#include <LibJS/Runtime/Shape.h>
#include <LibJS/Runtime/StringConstructor.h>
#include <LibJS/Runtime/StringIteratorPrototype.h>
#include <LibJS/Runtime/StringPrototype.h>
#include <LibJS/Runtime/SymbolConstructor.h>
#include <LibJS/Runtime/SymbolPrototype.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/TypedArrayConstructor.h>
#include <LibJS/Runtime/TypedArrayPrototype.h>
#include <LibJS/Runtime/Value.h>
#include <ctype.h>
namespace JS {
GlobalObject::GlobalObject()
: ScopeObject(GlobalObjectTag::Tag)
, m_console(make<Console>(*this))
{
}
void GlobalObject::initialize()
{
auto& vm = this->vm();
ensure_shape_is_unique();
// These are done first since other prototypes depend on their presence.
m_empty_object_shape = heap().allocate_without_global_object<Shape>(*this);
m_object_prototype = heap().allocate_without_global_object<ObjectPrototype>(*this);
m_function_prototype = heap().allocate_without_global_object<FunctionPrototype>(*this);
m_new_object_shape = vm.heap().allocate_without_global_object<Shape>(*this);
m_new_object_shape->set_prototype_without_transition(m_object_prototype);
m_new_script_function_prototype_object_shape = vm.heap().allocate_without_global_object<Shape>(*this);
m_new_script_function_prototype_object_shape->set_prototype_without_transition(m_object_prototype);
m_new_script_function_prototype_object_shape->add_property_without_transition(vm.names.constructor, Attribute::Writable | Attribute::Configurable);
static_cast<FunctionPrototype*>(m_function_prototype)->initialize(*this);
static_cast<ObjectPrototype*>(m_object_prototype)->initialize(*this);
set_prototype(m_object_prototype);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
if (!m_##snake_name##_prototype) \
m_##snake_name##_prototype = heap().allocate<PrototypeName>(*this, *this);
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(ClassName, snake_name) \
if (!m_##snake_name##_prototype) \
m_##snake_name##_prototype = heap().allocate<ClassName##Prototype>(*this, *this);
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.gc, gc, 0, attr);
define_native_function(vm.names.isNaN, is_nan, 1, attr);
define_native_function(vm.names.isFinite, is_finite, 1, attr);
define_native_function(vm.names.parseFloat, parse_float, 1, attr);
define_native_function(vm.names.parseInt, parse_int, 1, attr);
define_property(vm.names.NaN, js_nan(), 0);
define_property(vm.names.Infinity, js_infinity(), 0);
define_property(vm.names.undefined, js_undefined(), 0);
define_property(vm.names.globalThis, this, attr);
define_property(vm.names.console, heap().allocate<ConsoleObject>(*this, *this), attr);
define_property(vm.names.Math, heap().allocate<MathObject>(*this, *this), attr);
define_property(vm.names.JSON, heap().allocate<JSONObject>(*this, *this), attr);
define_property(vm.names.Reflect, heap().allocate<ReflectObject>(*this, *this), attr);
add_constructor(vm.names.Array, m_array_constructor, m_array_prototype);
add_constructor(vm.names.ArrayBuffer, m_array_buffer_constructor, m_array_buffer_prototype);
add_constructor(vm.names.BigInt, m_bigint_constructor, m_bigint_prototype);
add_constructor(vm.names.Boolean, m_boolean_constructor, m_boolean_prototype);
add_constructor(vm.names.Date, m_date_constructor, m_date_prototype);
add_constructor(vm.names.Error, m_error_constructor, m_error_prototype);
add_constructor(vm.names.Function, m_function_constructor, m_function_prototype);
add_constructor(vm.names.Number, m_number_constructor, m_number_prototype);
add_constructor(vm.names.Object, m_object_constructor, m_object_prototype);
add_constructor(vm.names.Proxy, m_proxy_constructor, nullptr);
add_constructor(vm.names.RegExp, m_regexp_constructor, m_regexp_prototype);
add_constructor(vm.names.String, m_string_constructor, m_string_prototype);
add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype);
initialize_constructor(vm.names.TypedArray, m_typed_array_constructor, m_typed_array_prototype);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
add_constructor(vm.names.ClassName, m_##snake_name##_constructor, m_##snake_name##_prototype);
JS_ENUMERATE_ERROR_SUBCLASSES
JS_ENUMERATE_TYPED_ARRAYS
#undef __JS_ENUMERATE
}
GlobalObject::~GlobalObject()
{
}
void GlobalObject::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_empty_object_shape);
visitor.visit(m_new_object_shape);
visitor.visit(m_new_script_function_prototype_object_shape);
visitor.visit(m_proxy_constructor);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
visitor.visit(m_##snake_name##_constructor);
JS_ENUMERATE_ERROR_SUBCLASSES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(ClassName, snake_name) \
visitor.visit(m_##snake_name##_prototype);
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
}
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::gc)
{
dbgln("Forced garbage collection requested!");
vm.heap().collect_garbage();
return js_undefined();
}
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::is_nan)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
return Value(number.is_nan());
}
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::is_finite)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
return Value(number.is_finite_number());
}
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::parse_float)
{
if (vm.argument(0).is_number())
return vm.argument(0);
auto string = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
for (size_t length = string.length(); length > 0; --length) {
// This can't throw, so no exception check is fine.
auto number = Value(js_string(vm, string.substring(0, length))).to_number(global_object);
if (!number.is_nan())
return number;
}
return js_nan();
}
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::parse_int)
{
// 18.2.5 parseInt ( string, radix )
auto input_string = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
// FIXME: There's a bunch of unnecessary string copying here.
double sign = 1;
auto s = input_string.trim_whitespace(TrimMode::Left);
if (!s.is_empty() && s[0] == '-')
sign = -1;
if (!s.is_empty() && (s[0] == '+' || s[0] == '-'))
s = s.substring(1, s.length() - 1);
auto radix = vm.argument(1).to_i32(global_object);
if (vm.exception())
return {};
bool strip_prefix = true;
if (radix != 0) {
if (radix < 2 || radix > 36)
return js_nan();
if (radix != 16)
strip_prefix = false;
} else {
radix = 10;
}
if (strip_prefix) {
if (s.length() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
s = s.substring(2, s.length() - 2);
radix = 16;
}
}
auto parse_digit = [&](u32 codepoint, i32 radix) -> Optional<i32> {
i32 digit = -1;
if (isdigit(codepoint))
digit = codepoint - '0';
else if (islower(codepoint))
digit = 10 + (codepoint - 'a');
else if (isupper(codepoint))
digit = 10 + (codepoint - 'A');
if (digit == -1 || digit >= radix)
return {};
return digit;
};
bool had_digits = false;
double number = 0;
for (auto codepoint : Utf8View(s)) {
auto digit = parse_digit(codepoint, radix);
if (!digit.has_value())
break;
had_digits = true;
number *= radix;
number += digit.value();
}
if (!had_digits)
return js_nan();
return Value(sign * number);
}
Optional<Variable> GlobalObject::get_from_scope(const FlyString& name) const
{
auto value = get(name);
if (value.is_empty())
return {};
return Variable { value, DeclarationKind::Var };
}
void GlobalObject::put_to_scope(const FlyString& name, Variable variable)
{
put(name, variable.value);
}
bool GlobalObject::has_this_binding() const
{
return true;
}
Value GlobalObject::get_this_binding(GlobalObject&) const
{
return Value(this);
}
}

View file

@ -0,0 +1,133 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/ScopeObject.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
class GlobalObject : public ScopeObject {
JS_OBJECT(GlobalObject, ScopeObject);
public:
explicit GlobalObject();
virtual void initialize();
virtual ~GlobalObject() override;
virtual Optional<Variable> get_from_scope(const FlyString&) const override;
virtual void put_to_scope(const FlyString&, Variable) override;
virtual bool has_this_binding() const override;
virtual Value get_this_binding(GlobalObject&) const override;
Console& console() { return *m_console; }
Shape* empty_object_shape() { return m_empty_object_shape; }
Shape* new_object_shape() { return m_new_object_shape; }
Shape* new_script_function_prototype_object_shape() { return m_new_script_function_prototype_object_shape; }
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
ProxyConstructor* proxy_constructor() { return m_proxy_constructor; }
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(ClassName, snake_name) \
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
protected:
virtual void visit_edges(Visitor&) override;
template<typename ConstructorType>
void initialize_constructor(const FlyString& property_name, ConstructorType*&, Object* prototype);
template<typename ConstructorType>
void add_constructor(const FlyString& property_name, ConstructorType*&, Object* prototype);
private:
JS_DECLARE_NATIVE_FUNCTION(gc);
JS_DECLARE_NATIVE_FUNCTION(is_nan);
JS_DECLARE_NATIVE_FUNCTION(is_finite);
JS_DECLARE_NATIVE_FUNCTION(parse_float);
JS_DECLARE_NATIVE_FUNCTION(parse_int);
NonnullOwnPtr<Console> m_console;
Shape* m_empty_object_shape { nullptr };
Shape* m_new_object_shape { nullptr };
Shape* m_new_script_function_prototype_object_shape { nullptr };
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
ProxyConstructor* m_proxy_constructor { nullptr };
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ConstructorName* m_##snake_name##_constructor { nullptr }; \
Object* m_##snake_name##_prototype { nullptr };
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(ClassName, snake_name) \
Object* m_##snake_name##_prototype { nullptr };
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
};
template<typename ConstructorType>
inline void GlobalObject::initialize_constructor(const FlyString& property_name, ConstructorType*& constructor, Object* prototype)
{
auto& vm = this->vm();
constructor = heap().allocate<ConstructorType>(*this, *this);
constructor->define_property(vm.names.name, js_string(heap(), property_name), Attribute::Configurable);
if (vm.exception())
return;
if (prototype) {
prototype->define_property(vm.names.constructor, constructor, Attribute::Writable | Attribute::Configurable);
if (vm.exception())
return;
}
}
template<typename ConstructorType>
inline void GlobalObject::add_constructor(const FlyString& property_name, ConstructorType*& constructor, Object* prototype)
{
initialize_constructor(property_name, constructor, prototype);
define_property(property_name, constructor, Attribute::Writable | Attribute::Configurable);
}
inline GlobalObject* Shape::global_object() const
{
return static_cast<GlobalObject*>(m_global_object);
}
}

View file

@ -0,0 +1,396 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <AK/QuickSort.h>
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/IndexedProperties.h>
namespace JS {
SimpleIndexedPropertyStorage::SimpleIndexedPropertyStorage(Vector<Value>&& initial_values)
: m_array_size(initial_values.size())
, m_packed_elements(move(initial_values))
{
}
bool SimpleIndexedPropertyStorage::has_index(u32 index) const
{
return index < m_array_size && !m_packed_elements[index].is_empty();
}
Optional<ValueAndAttributes> SimpleIndexedPropertyStorage::get(u32 index) const
{
if (index >= m_array_size)
return {};
return ValueAndAttributes { m_packed_elements[index], default_attributes };
}
void SimpleIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
{
ASSERT(attributes == default_attributes);
ASSERT(index < SPARSE_ARRAY_THRESHOLD);
if (index >= m_array_size) {
m_array_size = index + 1;
if (index >= m_packed_elements.size())
m_packed_elements.resize(index + MIN_PACKED_RESIZE_AMOUNT >= SPARSE_ARRAY_THRESHOLD ? SPARSE_ARRAY_THRESHOLD : index + MIN_PACKED_RESIZE_AMOUNT);
}
m_packed_elements[index] = value;
}
void SimpleIndexedPropertyStorage::remove(u32 index)
{
if (index < m_array_size)
m_packed_elements[index] = {};
}
void SimpleIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
{
ASSERT(attributes == default_attributes);
ASSERT(index < SPARSE_ARRAY_THRESHOLD);
m_array_size++;
ASSERT(m_array_size <= SPARSE_ARRAY_THRESHOLD);
m_packed_elements.insert(index, value);
}
ValueAndAttributes SimpleIndexedPropertyStorage::take_first()
{
m_array_size--;
return { m_packed_elements.take_first(), default_attributes };
}
ValueAndAttributes SimpleIndexedPropertyStorage::take_last()
{
m_array_size--;
auto last_element = m_packed_elements[m_array_size];
m_packed_elements[m_array_size] = {};
return { last_element, default_attributes };
}
void SimpleIndexedPropertyStorage::set_array_like_size(size_t new_size)
{
ASSERT(new_size <= SPARSE_ARRAY_THRESHOLD);
m_array_size = new_size;
m_packed_elements.resize(new_size);
}
GenericIndexedPropertyStorage::GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&& storage)
{
m_array_size = storage.array_like_size();
for (auto& element : move(storage.m_packed_elements))
m_packed_elements.append({ element, default_attributes });
}
bool GenericIndexedPropertyStorage::has_index(u32 index) const
{
if (index < SPARSE_ARRAY_THRESHOLD)
return index < m_packed_elements.size() && !m_packed_elements[index].value.is_empty();
return m_sparse_elements.contains(index);
}
Optional<ValueAndAttributes> GenericIndexedPropertyStorage::get(u32 index) const
{
if (index >= m_array_size)
return {};
if (index < SPARSE_ARRAY_THRESHOLD) {
if (index >= m_packed_elements.size())
return {};
return m_packed_elements[index];
}
return m_sparse_elements.get(index);
}
void GenericIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
{
if (index >= m_array_size)
m_array_size = index + 1;
if (index < SPARSE_ARRAY_THRESHOLD) {
if (index >= m_packed_elements.size())
m_packed_elements.resize(index + MIN_PACKED_RESIZE_AMOUNT >= SPARSE_ARRAY_THRESHOLD ? SPARSE_ARRAY_THRESHOLD : index + MIN_PACKED_RESIZE_AMOUNT);
m_packed_elements[index] = { value, attributes };
} else {
m_sparse_elements.set(index, { value, attributes });
}
}
void GenericIndexedPropertyStorage::remove(u32 index)
{
if (index >= m_array_size)
return;
if (index + 1 == m_array_size) {
take_last();
return;
}
if (index < SPARSE_ARRAY_THRESHOLD) {
if (index < m_packed_elements.size())
m_packed_elements[index] = {};
} else {
m_sparse_elements.remove(index);
}
}
void GenericIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
{
if (index >= m_array_size) {
put(index, value, attributes);
return;
}
m_array_size++;
if (!m_sparse_elements.is_empty()) {
HashMap<u32, ValueAndAttributes> new_sparse_elements;
for (auto& entry : m_sparse_elements)
new_sparse_elements.set(entry.key >= index ? entry.key + 1 : entry.key, entry.value);
m_sparse_elements = move(new_sparse_elements);
}
if (index < SPARSE_ARRAY_THRESHOLD) {
m_packed_elements.insert(index, { value, attributes });
} else {
m_sparse_elements.set(index, { value, attributes });
}
}
ValueAndAttributes GenericIndexedPropertyStorage::take_first()
{
ASSERT(m_array_size > 0);
m_array_size--;
if (!m_sparse_elements.is_empty()) {
HashMap<u32, ValueAndAttributes> new_sparse_elements;
for (auto& entry : m_sparse_elements)
new_sparse_elements.set(entry.key - 1, entry.value);
m_sparse_elements = move(new_sparse_elements);
}
return m_packed_elements.take_first();
}
ValueAndAttributes GenericIndexedPropertyStorage::take_last()
{
ASSERT(m_array_size > 0);
m_array_size--;
if (m_array_size <= SPARSE_ARRAY_THRESHOLD) {
auto last_element = m_packed_elements[m_array_size];
m_packed_elements[m_array_size] = {};
return last_element;
} else {
auto result = m_sparse_elements.get(m_array_size);
m_sparse_elements.remove(m_array_size);
ASSERT(result.has_value());
return result.value();
}
}
void GenericIndexedPropertyStorage::set_array_like_size(size_t new_size)
{
m_array_size = new_size;
if (new_size < SPARSE_ARRAY_THRESHOLD) {
m_packed_elements.resize(new_size);
m_sparse_elements.clear();
} else {
m_packed_elements.resize(SPARSE_ARRAY_THRESHOLD);
HashMap<u32, ValueAndAttributes> new_sparse_elements;
for (auto& entry : m_sparse_elements) {
if (entry.key < new_size)
new_sparse_elements.set(entry.key, entry.value);
}
m_sparse_elements = move(new_sparse_elements);
}
}
IndexedPropertyIterator::IndexedPropertyIterator(const IndexedProperties& indexed_properties, u32 staring_index, bool skip_empty)
: m_indexed_properties(indexed_properties)
, m_index(staring_index)
, m_skip_empty(skip_empty)
{
if (m_skip_empty)
skip_empty_indices();
}
IndexedPropertyIterator& IndexedPropertyIterator::operator++()
{
m_index++;
if (m_skip_empty)
skip_empty_indices();
return *this;
}
IndexedPropertyIterator& IndexedPropertyIterator::operator*()
{
return *this;
}
bool IndexedPropertyIterator::operator!=(const IndexedPropertyIterator& other) const
{
return m_index != other.m_index;
}
ValueAndAttributes IndexedPropertyIterator::value_and_attributes(Object* this_object, bool evaluate_accessors)
{
if (m_index < m_indexed_properties.array_like_size())
return m_indexed_properties.get(this_object, m_index, evaluate_accessors).value_or({});
return {};
}
void IndexedPropertyIterator::skip_empty_indices()
{
auto indices = m_indexed_properties.indices();
for (auto i : indices) {
if (i < m_index)
continue;
m_index = i;
return;
}
m_index = m_indexed_properties.array_like_size();
}
Optional<ValueAndAttributes> IndexedProperties::get(Object* this_object, u32 index, bool evaluate_accessors) const
{
auto result = m_storage->get(index);
if (!evaluate_accessors)
return result;
if (!result.has_value())
return {};
auto& value = result.value();
if (value.value.is_accessor()) {
ASSERT(this_object);
auto& accessor = value.value.as_accessor();
return ValueAndAttributes { accessor.call_getter(this_object), value.attributes };
}
return result;
}
void IndexedProperties::put(Object* this_object, u32 index, Value value, PropertyAttributes attributes, bool evaluate_accessors)
{
if (m_storage->is_simple_storage() && (index >= SPARSE_ARRAY_THRESHOLD || attributes != default_attributes))
switch_to_generic_storage();
if (m_storage->is_simple_storage() || !evaluate_accessors) {
m_storage->put(index, value, attributes);
return;
}
auto value_here = m_storage->get(index);
if (value_here.has_value() && value_here.value().value.is_accessor()) {
ASSERT(this_object);
value_here.value().value.as_accessor().call_setter(this_object, value);
} else {
m_storage->put(index, value, attributes);
}
}
bool IndexedProperties::remove(u32 index)
{
auto result = m_storage->get(index);
if (!result.has_value())
return true;
if (!result.value().attributes.is_configurable())
return false;
m_storage->remove(index);
return true;
}
void IndexedProperties::insert(u32 index, Value value, PropertyAttributes attributes)
{
if (m_storage->is_simple_storage() && (index >= SPARSE_ARRAY_THRESHOLD || attributes != default_attributes || array_like_size() == SPARSE_ARRAY_THRESHOLD))
switch_to_generic_storage();
m_storage->insert(index, move(value), attributes);
}
ValueAndAttributes IndexedProperties::take_first(Object* this_object)
{
auto first = m_storage->take_first();
if (first.value.is_accessor())
return { first.value.as_accessor().call_getter(this_object), first.attributes };
return first;
}
ValueAndAttributes IndexedProperties::take_last(Object* this_object)
{
auto last = m_storage->take_last();
if (last.value.is_accessor())
return { last.value.as_accessor().call_getter(this_object), last.attributes };
return last;
}
void IndexedProperties::append_all(Object* this_object, const IndexedProperties& properties, bool evaluate_accessors)
{
if (m_storage->is_simple_storage() && !properties.m_storage->is_simple_storage())
switch_to_generic_storage();
for (auto it = properties.begin(false); it != properties.end(); ++it) {
const auto& element = it.value_and_attributes(this_object, evaluate_accessors);
if (this_object && this_object->vm().exception())
return;
m_storage->put(m_storage->array_like_size(), element.value, element.attributes);
}
}
void IndexedProperties::set_array_like_size(size_t new_size)
{
if (m_storage->is_simple_storage() && new_size > SPARSE_ARRAY_THRESHOLD)
switch_to_generic_storage();
m_storage->set_array_like_size(new_size);
}
Vector<u32> IndexedProperties::indices() const
{
Vector<u32> indices;
if (m_storage->is_simple_storage()) {
const auto& storage = static_cast<const SimpleIndexedPropertyStorage&>(*m_storage);
const auto& elements = storage.elements();
indices.ensure_capacity(storage.array_like_size());
for (size_t i = 0; i < elements.size(); ++i) {
if (!elements.at(i).is_empty())
indices.unchecked_append(i);
}
} else {
const auto& storage = static_cast<const GenericIndexedPropertyStorage&>(*m_storage);
const auto packed_elements = storage.packed_elements();
indices.ensure_capacity(storage.array_like_size());
for (size_t i = 0; i < packed_elements.size(); ++i) {
if (!packed_elements.at(i).value.is_empty())
indices.unchecked_append(i);
}
auto sparse_elements_keys = storage.sparse_elements().keys();
quick_sort(sparse_elements_keys);
indices.append(move(sparse_elements_keys));
}
return indices;
}
void IndexedProperties::switch_to_generic_storage()
{
auto& storage = static_cast<SimpleIndexedPropertyStorage&>(*m_storage);
m_storage = make<GenericIndexedPropertyStorage>(move(storage));
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <AK/NonnullOwnPtr.h>
#include <LibJS/Runtime/Shape.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
const u32 SPARSE_ARRAY_THRESHOLD = 200;
const u32 MIN_PACKED_RESIZE_AMOUNT = 20;
struct ValueAndAttributes {
Value value;
PropertyAttributes attributes { default_attributes };
};
class IndexedProperties;
class IndexedPropertyIterator;
class GenericIndexedPropertyStorage;
class IndexedPropertyStorage {
public:
virtual ~IndexedPropertyStorage() {};
virtual bool has_index(u32 index) const = 0;
virtual Optional<ValueAndAttributes> get(u32 index) const = 0;
virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) = 0;
virtual void remove(u32 index) = 0;
virtual void insert(u32 index, Value value, PropertyAttributes attributes = default_attributes) = 0;
virtual ValueAndAttributes take_first() = 0;
virtual ValueAndAttributes take_last() = 0;
virtual size_t size() const = 0;
virtual size_t array_like_size() const = 0;
virtual void set_array_like_size(size_t new_size) = 0;
virtual bool is_simple_storage() const { return false; }
};
class SimpleIndexedPropertyStorage final : public IndexedPropertyStorage {
public:
SimpleIndexedPropertyStorage() = default;
explicit SimpleIndexedPropertyStorage(Vector<Value>&& initial_values);
virtual bool has_index(u32 index) const override;
virtual Optional<ValueAndAttributes> get(u32 index) const override;
virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
virtual void remove(u32 index) override;
virtual void insert(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
virtual ValueAndAttributes take_first() override;
virtual ValueAndAttributes take_last() override;
virtual size_t size() const override { return m_packed_elements.size(); }
virtual size_t array_like_size() const override { return m_array_size; }
virtual void set_array_like_size(size_t new_size) override;
virtual bool is_simple_storage() const override { return true; }
const Vector<Value>& elements() const { return m_packed_elements; }
private:
friend GenericIndexedPropertyStorage;
size_t m_array_size { 0 };
Vector<Value> m_packed_elements;
};
class GenericIndexedPropertyStorage final : public IndexedPropertyStorage {
public:
explicit GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&&);
virtual bool has_index(u32 index) const override;
virtual Optional<ValueAndAttributes> get(u32 index) const override;
virtual void put(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
virtual void remove(u32 index) override;
virtual void insert(u32 index, Value value, PropertyAttributes attributes = default_attributes) override;
virtual ValueAndAttributes take_first() override;
virtual ValueAndAttributes take_last() override;
virtual size_t size() const override { return m_packed_elements.size() + m_sparse_elements.size(); }
virtual size_t array_like_size() const override { return m_array_size; }
virtual void set_array_like_size(size_t new_size) override;
const Vector<ValueAndAttributes>& packed_elements() const { return m_packed_elements; }
const HashMap<u32, ValueAndAttributes>& sparse_elements() const { return m_sparse_elements; }
private:
size_t m_array_size { 0 };
Vector<ValueAndAttributes> m_packed_elements;
HashMap<u32, ValueAndAttributes> m_sparse_elements;
};
class IndexedPropertyIterator {
public:
IndexedPropertyIterator(const IndexedProperties&, u32 starting_index, bool skip_empty);
IndexedPropertyIterator& operator++();
IndexedPropertyIterator& operator*();
bool operator!=(const IndexedPropertyIterator&) const;
u32 index() const { return m_index; };
ValueAndAttributes value_and_attributes(Object* this_object, bool evaluate_accessors = true);
private:
void skip_empty_indices();
const IndexedProperties& m_indexed_properties;
u32 m_index;
bool m_skip_empty;
};
class IndexedProperties {
public:
IndexedProperties() = default;
IndexedProperties(Vector<Value>&& values)
: m_storage(make<SimpleIndexedPropertyStorage>(move(values)))
{
}
bool has_index(u32 index) const { return m_storage->has_index(index); }
Optional<ValueAndAttributes> get(Object* this_object, u32 index, bool evaluate_accessors = true) const;
void put(Object* this_object, u32 index, Value value, PropertyAttributes attributes = default_attributes, bool evaluate_accessors = true);
bool remove(u32 index);
void insert(u32 index, Value value, PropertyAttributes attributes = default_attributes);
ValueAndAttributes take_first(Object* this_object);
ValueAndAttributes take_last(Object* this_object);
void append(Value value, PropertyAttributes attributes = default_attributes) { put(nullptr, array_like_size(), value, attributes, false); }
void append_all(Object* this_object, const IndexedProperties& properties, bool evaluate_accessors = true);
IndexedPropertyIterator begin(bool skip_empty = true) const { return IndexedPropertyIterator(*this, 0, skip_empty); };
IndexedPropertyIterator end() const { return IndexedPropertyIterator(*this, array_like_size(), false); };
bool is_empty() const { return array_like_size() == 0; }
size_t array_like_size() const { return m_storage->array_like_size(); }
void set_array_like_size(size_t);
Vector<u32> indices() const;
template<typename Callback>
void for_each_value(Callback callback)
{
if (m_storage->is_simple_storage()) {
for (auto& value : static_cast<SimpleIndexedPropertyStorage&>(*m_storage).elements())
callback(value);
} else {
for (auto& element : static_cast<const GenericIndexedPropertyStorage&>(*m_storage).packed_elements())
callback(element.value);
for (auto& element : static_cast<const GenericIndexedPropertyStorage&>(*m_storage).sparse_elements())
callback(element.value.value);
}
}
private:
void switch_to_generic_storage();
NonnullOwnPtr<IndexedPropertyStorage> m_storage { make<SimpleIndexedPropertyStorage>() };
};
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
namespace JS {
Object* get_iterator(GlobalObject& global_object, Value value, String hint, Value method)
{
auto& vm = global_object.vm();
ASSERT(hint == "sync" || hint == "async");
if (method.is_empty()) {
if (hint == "async")
TODO();
auto object = value.to_object(global_object);
if (!object)
return {};
method = object->get(global_object.vm().well_known_symbol_iterator());
if (vm.exception())
return {};
}
if (!method.is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotIterable, value.to_string_without_side_effects());
return nullptr;
}
auto iterator = vm.call(method.as_function(), value);
if (vm.exception())
return {};
if (!iterator.is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotIterable, value.to_string_without_side_effects());
return nullptr;
}
return &iterator.as_object();
}
Object* iterator_next(Object& iterator, Value value)
{
auto& vm = iterator.vm();
auto& global_object = iterator.global_object();
auto next_method = iterator.get(vm.names.next);
if (vm.exception())
return {};
if (!next_method.is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::IterableNextNotAFunction);
return nullptr;
}
Value result;
if (value.is_empty())
result = vm.call(next_method.as_function(), &iterator);
else
result = vm.call(next_method.as_function(), &iterator, value);
if (vm.exception())
return {};
if (!result.is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::IterableNextBadReturn);
return nullptr;
}
return &result.as_object();
}
void iterator_close([[maybe_unused]] Object& iterator)
{
TODO();
}
Value create_iterator_result_object(GlobalObject& global_object, Value value, bool done)
{
auto& vm = global_object.vm();
auto* object = Object::create_empty(global_object);
object->define_property(vm.names.value, value);
object->define_property(vm.names.done, Value(done));
return object;
}
void get_iterator_values(GlobalObject& global_object, Value value, AK::Function<IterationDecision(Value)> callback)
{
auto& vm = global_object.vm();
auto iterator = get_iterator(global_object, value);
if (!iterator)
return;
while (true) {
auto next_object = iterator_next(*iterator);
if (!next_object)
return;
auto done_property = next_object->get(vm.names.done);
if (vm.exception())
return;
if (!done_property.is_empty() && done_property.to_boolean())
return;
auto next_value = next_object->get(vm.names.value);
if (vm.exception())
return;
auto result = callback(next_value);
if (result == IterationDecision::Break)
return;
ASSERT(result == IterationDecision::Continue);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <AK/Function.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
// Common iterator operations defined in ECMA262 7.4
// https://tc39.es/ecma262/#sec-operations-on-iterator-objects
Object* get_iterator(GlobalObject&, Value value, String hint = "sync", Value method = {});
bool is_iterator_complete(Object& iterator_result);
Value create_iterator_result_object(GlobalObject&, Value value, bool done);
Object* iterator_next(Object& iterator, Value value = {});
void iterator_close(Object& iterator);
void get_iterator_values(GlobalObject&, Value value, AK::Function<IterationDecision(Value)> callback);
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorPrototype.h>
namespace JS {
IteratorPrototype::IteratorPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void IteratorPrototype::initialize(GlobalObject& global_object)
{
Object::initialize(global_object);
define_native_function(global_object.vm().well_known_symbol_iterator(), symbol_iterator, 0, Attribute::Writable | Attribute::Enumerable);
}
IteratorPrototype::~IteratorPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::symbol_iterator)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
return this_object;
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class IteratorPrototype : public Object {
JS_OBJECT(IteratorPrototype, Object)
public:
IteratorPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~IteratorPrototype() override;
private:
JS_DECLARE_NATIVE_FUNCTION(symbol_iterator);
};
}

View file

@ -0,0 +1,507 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <AK/Function.h>
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonParser.h>
#include <AK/StringBuilder.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/BigIntObject.h>
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/JSONObject.h>
#include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/StringObject.h>
namespace JS {
JSONObject::JSONObject(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void JSONObject::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.stringify, stringify, 3, attr);
define_native_function(vm.names.parse, parse, 2, attr);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "JSON"), Attribute::Configurable);
}
JSONObject::~JSONObject()
{
}
String JSONObject::stringify_impl(GlobalObject& global_object, Value value, Value replacer, Value space)
{
auto& vm = global_object.vm();
StringifyState state;
if (replacer.is_object()) {
if (replacer.as_object().is_function()) {
state.replacer_function = &replacer.as_function();
} else if (replacer.is_array()) {
auto& replacer_object = replacer.as_object();
auto replacer_length = length_of_array_like(global_object, replacer_object);
if (vm.exception())
return {};
Vector<String> list;
for (size_t i = 0; i < replacer_length; ++i) {
auto replacer_value = replacer_object.get(i);
if (vm.exception())
return {};
String item;
if (replacer_value.is_string() || replacer_value.is_number()) {
item = replacer_value.to_string(global_object);
if (vm.exception())
return {};
} else if (replacer_value.is_object()) {
auto& value_object = replacer_value.as_object();
if (is<StringObject>(value_object) || is<NumberObject>(value_object)) {
item = value_object.value_of().to_string(global_object);
if (vm.exception())
return {};
}
}
if (!item.is_null() && !list.contains_slow(item)) {
list.append(item);
}
}
state.property_list = list;
}
}
if (space.is_object()) {
auto& space_obj = space.as_object();
if (is<StringObject>(space_obj) || is<NumberObject>(space_obj))
space = space_obj.value_of();
}
if (space.is_number()) {
StringBuilder gap_builder;
auto gap_size = min(10, space.as_i32());
for (auto i = 0; i < gap_size; ++i)
gap_builder.append(' ');
state.gap = gap_builder.to_string();
} else if (space.is_string()) {
auto string = space.as_string().string();
if (string.length() <= 10) {
state.gap = string;
} else {
state.gap = string.substring(0, 10);
}
} else {
state.gap = String::empty();
}
auto* wrapper = Object::create_empty(global_object);
wrapper->define_property(String::empty(), value);
if (vm.exception())
return {};
auto result = serialize_json_property(global_object, state, String::empty(), wrapper);
if (vm.exception())
return {};
if (result.is_null())
return {};
return result;
}
JS_DEFINE_NATIVE_FUNCTION(JSONObject::stringify)
{
if (!vm.argument_count())
return js_undefined();
auto value = vm.argument(0);
auto replacer = vm.argument(1);
auto space = vm.argument(2);
auto string = stringify_impl(global_object, value, replacer, space);
if (string.is_null())
return js_undefined();
return js_string(vm, string);
}
String JSONObject::serialize_json_property(GlobalObject& global_object, StringifyState& state, const PropertyName& key, Object* holder)
{
auto& vm = global_object.vm();
auto value = holder->get(key);
if (vm.exception())
return {};
if (value.is_object()) {
auto to_json = value.as_object().get(vm.names.toJSON);
if (vm.exception())
return {};
if (to_json.is_function()) {
value = vm.call(to_json.as_function(), value, js_string(vm, key.to_string()));
if (vm.exception())
return {};
}
}
if (state.replacer_function) {
value = vm.call(*state.replacer_function, holder, js_string(vm, key.to_string()), value);
if (vm.exception())
return {};
}
if (value.is_object()) {
auto& value_object = value.as_object();
if (is<NumberObject>(value_object) || is<BooleanObject>(value_object) || is<StringObject>(value_object) || is<BigIntObject>(value_object))
value = value_object.value_of();
}
if (value.is_null())
return "null";
if (value.is_boolean())
return value.as_bool() ? "true" : "false";
if (value.is_string())
return quote_json_string(value.as_string().string());
if (value.is_number()) {
if (value.is_finite_number())
return value.to_string(global_object);
return "null";
}
if (value.is_object() && !value.is_function()) {
if (value.is_array())
return serialize_json_array(global_object, state, static_cast<Array&>(value.as_object()));
return serialize_json_object(global_object, state, value.as_object());
}
if (value.is_bigint())
vm.throw_exception<TypeError>(global_object, ErrorType::JsonBigInt);
return {};
}
String JSONObject::serialize_json_object(GlobalObject& global_object, StringifyState& state, Object& object)
{
auto& vm = global_object.vm();
if (state.seen_objects.contains(&object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::JsonCircular);
return {};
}
state.seen_objects.set(&object);
String previous_indent = state.indent;
state.indent = String::formatted("{}{}", state.indent, state.gap);
Vector<String> property_strings;
auto process_property = [&](const PropertyName& key) {
auto serialized_property_string = serialize_json_property(global_object, state, key, &object);
if (vm.exception())
return;
if (!serialized_property_string.is_null()) {
property_strings.append(String::formatted(
"{}:{}{}",
quote_json_string(key.to_string()),
state.gap.is_empty() ? "" : " ",
serialized_property_string));
}
};
if (state.property_list.has_value()) {
auto property_list = state.property_list.value();
for (auto& property : property_list) {
process_property(property);
if (vm.exception())
return {};
}
} else {
for (auto& entry : object.indexed_properties()) {
auto value_and_attributes = entry.value_and_attributes(&object);
if (!value_and_attributes.attributes.is_enumerable())
continue;
process_property(entry.index());
if (vm.exception())
return {};
}
for (auto& [key, metadata] : object.shape().property_table_ordered()) {
if (!metadata.attributes.is_enumerable())
continue;
process_property(key);
if (vm.exception())
return {};
}
}
StringBuilder builder;
if (property_strings.is_empty()) {
builder.append("{}");
} else {
bool first = true;
builder.append('{');
if (state.gap.is_empty()) {
for (auto& property_string : property_strings) {
if (!first)
builder.append(',');
first = false;
builder.append(property_string);
}
} else {
builder.append('\n');
builder.append(state.indent);
auto separator = String::formatted(",\n{}", state.indent);
for (auto& property_string : property_strings) {
if (!first)
builder.append(separator);
first = false;
builder.append(property_string);
}
builder.append('\n');
builder.append(previous_indent);
}
builder.append('}');
}
state.seen_objects.remove(&object);
state.indent = previous_indent;
return builder.to_string();
}
String JSONObject::serialize_json_array(GlobalObject& global_object, StringifyState& state, Object& object)
{
auto& vm = global_object.vm();
if (state.seen_objects.contains(&object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::JsonCircular);
return {};
}
state.seen_objects.set(&object);
String previous_indent = state.indent;
state.indent = String::formatted("{}{}", state.indent, state.gap);
Vector<String> property_strings;
auto length = length_of_array_like(global_object, object);
if (vm.exception())
return {};
for (size_t i = 0; i < length; ++i) {
if (vm.exception())
return {};
auto serialized_property_string = serialize_json_property(global_object, state, i, &object);
if (vm.exception())
return {};
if (serialized_property_string.is_null()) {
property_strings.append("null");
} else {
property_strings.append(serialized_property_string);
}
}
StringBuilder builder;
if (property_strings.is_empty()) {
builder.append("[]");
} else {
if (state.gap.is_empty()) {
builder.append('[');
bool first = true;
for (auto& property_string : property_strings) {
if (!first)
builder.append(',');
first = false;
builder.append(property_string);
}
builder.append(']');
} else {
builder.append("[\n");
builder.append(state.indent);
auto separator = String::formatted(",\n{}", state.indent);
bool first = true;
for (auto& property_string : property_strings) {
if (!first)
builder.append(separator);
first = false;
builder.append(property_string);
}
builder.append('\n');
builder.append(previous_indent);
builder.append(']');
}
}
state.seen_objects.remove(&object);
state.indent = previous_indent;
return builder.to_string();
}
String JSONObject::quote_json_string(String string)
{
// FIXME: Handle UTF16
StringBuilder builder;
builder.append('"');
for (auto& ch : string) {
switch (ch) {
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\f':
builder.append("\\f");
break;
case '\r':
builder.append("\\r");
break;
case '"':
builder.append("\\\"");
break;
case '\\':
builder.append("\\\\");
break;
default:
if (ch < 0x20) {
builder.append("\\u%#08x", ch);
} else {
builder.append(ch);
}
}
}
builder.append('"');
return builder.to_string();
}
JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
{
if (!vm.argument_count())
return js_undefined();
auto string = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
auto reviver = vm.argument(1);
auto json = JsonValue::from_string(string);
if (!json.has_value()) {
vm.throw_exception<SyntaxError>(global_object, ErrorType::JsonMalformed);
return {};
}
Value result = parse_json_value(global_object, json.value());
if (reviver.is_function()) {
auto* holder_object = Object::create_empty(global_object);
holder_object->define_property(String::empty(), result);
if (vm.exception())
return {};
return internalize_json_property(global_object, holder_object, String::empty(), reviver.as_function());
}
return result;
}
Value JSONObject::parse_json_value(GlobalObject& global_object, const JsonValue& value)
{
if (value.is_object())
return Value(parse_json_object(global_object, value.as_object()));
if (value.is_array())
return Value(parse_json_array(global_object, value.as_array()));
if (value.is_null())
return js_null();
#if !defined(KERNEL)
if (value.is_double())
return Value(value.as_double());
#endif
if (value.is_number())
return Value(value.to_i32(0));
if (value.is_string())
return js_string(global_object.heap(), value.to_string());
if (value.is_bool())
return Value(static_cast<bool>(value.as_bool()));
ASSERT_NOT_REACHED();
}
Object* JSONObject::parse_json_object(GlobalObject& global_object, const JsonObject& json_object)
{
auto* object = Object::create_empty(global_object);
json_object.for_each_member([&](auto& key, auto& value) {
object->define_property(key, parse_json_value(global_object, value));
});
return object;
}
Array* JSONObject::parse_json_array(GlobalObject& global_object, const JsonArray& json_array)
{
auto* array = Array::create(global_object);
size_t index = 0;
json_array.for_each([&](auto& value) {
array->define_property(index++, parse_json_value(global_object, value));
});
return array;
}
Value JSONObject::internalize_json_property(GlobalObject& global_object, Object* holder, const PropertyName& name, Function& reviver)
{
auto& vm = global_object.vm();
auto value = holder->get(name);
if (vm.exception())
return {};
if (value.is_object()) {
auto& value_object = value.as_object();
auto process_property = [&](const PropertyName& key) {
auto element = internalize_json_property(global_object, &value_object, key, reviver);
if (vm.exception())
return;
if (element.is_undefined()) {
value_object.delete_property(key);
} else {
value_object.define_property(key, element, default_attributes, false);
}
};
if (value_object.is_array()) {
auto length = length_of_array_like(global_object, value_object);
for (size_t i = 0; i < length; ++i) {
process_property(i);
if (vm.exception())
return {};
}
} else {
for (auto& entry : value_object.indexed_properties()) {
auto value_and_attributes = entry.value_and_attributes(&value_object);
if (!value_and_attributes.attributes.is_enumerable())
continue;
process_property(entry.index());
if (vm.exception())
return {};
}
for (auto& [key, metadata] : value_object.shape().property_table_ordered()) {
if (!metadata.attributes.is_enumerable())
continue;
process_property(key);
if (vm.exception())
return {};
}
}
}
return vm.call(reviver, Value(holder), js_string(vm, name.to_string()), value);
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class JSONObject final : public Object {
JS_OBJECT(JSONObject, Object);
public:
explicit JSONObject(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~JSONObject() override;
// The base implementation of stringify is exposed because it is used by
// test-js to communicate between the JS tests and the C++ test runner.
static String stringify_impl(GlobalObject&, Value value, Value replacer, Value space);
private:
struct StringifyState {
Function* replacer_function { nullptr };
HashTable<Object*> seen_objects;
String indent { String::empty() };
String gap;
Optional<Vector<String>> property_list;
};
// Stringify helpers
static String serialize_json_property(GlobalObject&, StringifyState&, const PropertyName& key, Object* holder);
static String serialize_json_object(GlobalObject&, StringifyState&, Object&);
static String serialize_json_array(GlobalObject&, StringifyState&, Object&);
static String quote_json_string(String);
// Parse helpers
static Object* parse_json_object(GlobalObject&, const JsonObject&);
static Array* parse_json_array(GlobalObject&, const JsonArray&);
static Value parse_json_value(GlobalObject&, const JsonValue&);
static Value internalize_json_property(GlobalObject&, Object* holder, const PropertyName& name, Function& reviver);
JS_DECLARE_NATIVE_FUNCTION(stringify);
JS_DECLARE_NATIVE_FUNCTION(parse);
};
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/LexicalEnvironment.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
LexicalEnvironment::LexicalEnvironment()
: ScopeObject(nullptr)
{
}
LexicalEnvironment::LexicalEnvironment(EnvironmentRecordType environment_record_type)
: ScopeObject(nullptr)
, m_environment_record_type(environment_record_type)
{
}
LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> variables, ScopeObject* parent_scope)
: ScopeObject(parent_scope)
, m_variables(move(variables))
{
}
LexicalEnvironment::LexicalEnvironment(HashMap<FlyString, Variable> variables, ScopeObject* parent_scope, EnvironmentRecordType environment_record_type)
: ScopeObject(parent_scope)
, m_environment_record_type(environment_record_type)
, m_variables(move(variables))
{
}
LexicalEnvironment::~LexicalEnvironment()
{
}
void LexicalEnvironment::visit_edges(Visitor& visitor)
{
Cell::visit_edges(visitor);
visitor.visit(m_this_value);
visitor.visit(m_home_object);
visitor.visit(m_new_target);
visitor.visit(m_current_function);
for (auto& it : m_variables)
visitor.visit(it.value.value);
}
Optional<Variable> LexicalEnvironment::get_from_scope(const FlyString& name) const
{
return m_variables.get(name);
}
void LexicalEnvironment::put_to_scope(const FlyString& name, Variable variable)
{
m_variables.set(name, variable);
}
bool LexicalEnvironment::has_super_binding() const
{
return m_environment_record_type == EnvironmentRecordType::Function && this_binding_status() != ThisBindingStatus::Lexical && m_home_object.is_object();
}
Value LexicalEnvironment::get_super_base()
{
ASSERT(has_super_binding());
if (m_home_object.is_object())
return m_home_object.as_object().prototype();
return {};
}
bool LexicalEnvironment::has_this_binding() const
{
// More like "is_capable_of_having_a_this_binding".
switch (m_environment_record_type) {
case EnvironmentRecordType::Declarative:
case EnvironmentRecordType::Object:
return false;
case EnvironmentRecordType::Function:
return this_binding_status() != ThisBindingStatus::Lexical;
case EnvironmentRecordType::Module:
return true;
}
ASSERT_NOT_REACHED();
}
Value LexicalEnvironment::get_this_binding(GlobalObject& global_object) const
{
ASSERT(has_this_binding());
if (this_binding_status() == ThisBindingStatus::Uninitialized) {
vm().throw_exception<ReferenceError>(global_object, ErrorType::ThisHasNotBeenInitialized);
return {};
}
return m_this_value;
}
void LexicalEnvironment::bind_this_value(GlobalObject& global_object, Value this_value)
{
ASSERT(has_this_binding());
if (m_this_binding_status == ThisBindingStatus::Initialized) {
vm().throw_exception<ReferenceError>(global_object, ErrorType::ThisIsAlreadyInitialized);
return;
}
m_this_value = this_value;
m_this_binding_status = ThisBindingStatus::Initialized;
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/FlyString.h>
#include <AK/HashMap.h>
#include <LibJS/Runtime/ScopeObject.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
class LexicalEnvironment final : public ScopeObject {
JS_OBJECT(LexicalEnvironment, ScopeObject);
public:
enum class ThisBindingStatus {
Lexical,
Initialized,
Uninitialized,
};
enum class EnvironmentRecordType {
Declarative,
Function,
Object,
Module,
};
LexicalEnvironment();
LexicalEnvironment(EnvironmentRecordType);
LexicalEnvironment(HashMap<FlyString, Variable> variables, ScopeObject* parent_scope);
LexicalEnvironment(HashMap<FlyString, Variable> variables, ScopeObject* parent_scope, EnvironmentRecordType);
virtual ~LexicalEnvironment() override;
// ^ScopeObject
virtual Optional<Variable> get_from_scope(const FlyString&) const override;
virtual void put_to_scope(const FlyString&, Variable) override;
virtual bool has_this_binding() const override;
virtual Value get_this_binding(GlobalObject&) const override;
void clear();
const HashMap<FlyString, Variable>& variables() const { return m_variables; }
void set_home_object(Value object) { m_home_object = object; }
bool has_super_binding() const;
Value get_super_base();
ThisBindingStatus this_binding_status() const { return m_this_binding_status; }
void bind_this_value(GlobalObject&, Value this_value);
// Not a standard operation.
void replace_this_binding(Value this_value) { m_this_value = this_value; }
Value new_target() const { return m_new_target; };
void set_new_target(Value new_target) { m_new_target = new_target; }
Function* current_function() const { return m_current_function; }
void set_current_function(Function& function) { m_current_function = &function; }
EnvironmentRecordType type() const { return m_environment_record_type; }
private:
virtual void visit_edges(Visitor&) override;
EnvironmentRecordType m_environment_record_type : 8 { EnvironmentRecordType::Declarative };
ThisBindingStatus m_this_binding_status : 8 { ThisBindingStatus::Uninitialized };
HashMap<FlyString, Variable> m_variables;
Value m_home_object;
Value m_this_value;
Value m_new_target;
// Corresponds to [[FunctionObject]]
Function* m_current_function { nullptr };
};
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/MarkedValueList.h>
namespace JS {
MarkedValueList::MarkedValueList(Heap& heap)
: m_heap(heap)
{
m_heap.did_create_marked_value_list({}, *this);
}
MarkedValueList::MarkedValueList(MarkedValueList&& other)
: AK::Vector<Value, 32>(move(static_cast<Vector<Value, 32>&>(other)))
, m_heap(other.m_heap)
{
m_heap.did_create_marked_value_list({}, *this);
}
MarkedValueList::~MarkedValueList()
{
m_heap.did_destroy_marked_value_list({}, *this);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/Noncopyable.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
class MarkedValueList : public AK::Vector<Value, 32> {
AK_MAKE_NONCOPYABLE(MarkedValueList);
public:
explicit MarkedValueList(Heap&);
MarkedValueList(MarkedValueList&&);
~MarkedValueList();
MarkedValueList& operator=(MarkedValueList&&) = delete;
Vector<Value, 32>& values() { return *this; }
MarkedValueList copy() const
{
MarkedValueList copy { m_heap };
copy.append(*this);
return copy;
}
private:
Heap& m_heap;
};
}

View file

@ -0,0 +1,504 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <AK/FlyString.h>
#include <AK/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/MathObject.h>
#include <math.h>
namespace JS {
MathObject::MathObject(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
}
void MathObject::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.abs, abs, 1, attr);
define_native_function(vm.names.random, random, 0, attr);
define_native_function(vm.names.sqrt, sqrt, 1, attr);
define_native_function(vm.names.floor, floor, 1, attr);
define_native_function(vm.names.ceil, ceil, 1, attr);
define_native_function(vm.names.round, round, 1, attr);
define_native_function(vm.names.max, max, 2, attr);
define_native_function(vm.names.min, min, 2, attr);
define_native_function(vm.names.trunc, trunc, 1, attr);
define_native_function(vm.names.sin, sin, 1, attr);
define_native_function(vm.names.cos, cos, 1, attr);
define_native_function(vm.names.tan, tan, 1, attr);
define_native_function(vm.names.pow, pow, 2, attr);
define_native_function(vm.names.exp, exp, 1, attr);
define_native_function(vm.names.expm1, expm1, 1, attr);
define_native_function(vm.names.sign, sign, 1, attr);
define_native_function(vm.names.clz32, clz32, 1, attr);
define_native_function(vm.names.acos, acos, 1, attr);
define_native_function(vm.names.acosh, acosh, 1, attr);
define_native_function(vm.names.asin, asin, 1, attr);
define_native_function(vm.names.asinh, asinh, 1, attr);
define_native_function(vm.names.atan, atan, 1, attr);
define_native_function(vm.names.atanh, atanh, 1, attr);
define_native_function(vm.names.log1p, log1p, 1, attr);
define_native_function(vm.names.cbrt, cbrt, 1, attr);
define_native_function(vm.names.atan2, atan2, 2, attr);
define_native_function(vm.names.fround, fround, 1, attr);
define_native_function(vm.names.hypot, hypot, 2, attr);
define_native_function(vm.names.log, log, 1, attr);
define_native_function(vm.names.log2, log2, 1, attr);
define_native_function(vm.names.log10, log10, 1, attr);
define_native_function(vm.names.sinh, sinh, 1, attr);
define_native_function(vm.names.cosh, cosh, 1, attr);
define_native_function(vm.names.tanh, tanh, 1, attr);
define_property(vm.names.E, Value(M_E), 0);
define_property(vm.names.LN2, Value(M_LN2), 0);
define_property(vm.names.LN10, Value(M_LN10), 0);
define_property(vm.names.LOG2E, Value(::log2(M_E)), 0);
define_property(vm.names.LOG10E, Value(::log10(M_E)), 0);
define_property(vm.names.PI, Value(M_PI), 0);
define_property(vm.names.SQRT1_2, Value(M_SQRT1_2), 0);
define_property(vm.names.SQRT2, Value(M_SQRT2), 0);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Math"), Attribute::Configurable);
}
MathObject::~MathObject()
{
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::abs)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(number.as_double() >= 0 ? number.as_double() : -number.as_double());
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::random)
{
#ifdef __serenity__
double r = (double)arc4random() / (double)UINT32_MAX;
#else
double r = (double)rand() / (double)RAND_MAX;
#endif
return Value(r);
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::sqrt)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::sqrt(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::floor)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::floor(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::ceil)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
auto number_double = number.as_double();
if (number_double < 0 && number_double > -1)
return Value(-0.f);
return Value(::ceil(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::round)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::round(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::max)
{
if (!vm.argument_count())
return js_negative_infinity();
auto max = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
for (size_t i = 1; i < vm.argument_count(); ++i) {
auto cur = vm.argument(i).to_number(global_object);
if (vm.exception())
return {};
max = Value(cur.as_double() > max.as_double() ? cur : max);
}
return max;
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::min)
{
if (!vm.argument_count())
return js_infinity();
auto min = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
for (size_t i = 1; i < vm.argument_count(); ++i) {
auto cur = vm.argument(i).to_number(global_object);
if (vm.exception())
return {};
min = Value(cur.as_double() < min.as_double() ? cur : min);
}
return min;
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::trunc)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
if (number.as_double() < 0)
return MathObject::ceil(vm, global_object);
return MathObject::floor(vm, global_object);
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::sin)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::sin(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::cos)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::cos(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::tan)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::tan(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::pow)
{
return JS::exp(global_object, vm.argument(0), vm.argument(1));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::exp)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::exp(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::expm1)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::expm1(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::sign)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_positive_zero())
return Value(0);
if (number.is_negative_zero())
return Value(-0.0);
if (number.as_double() > 0)
return Value(1);
if (number.as_double() < 0)
return Value(-1);
return js_nan();
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::clz32)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (!number.is_finite_number() || (unsigned)number.as_double() == 0)
return Value(32);
return Value(__builtin_clz((unsigned)number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::acos)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan() || number.as_double() > 1 || number.as_double() < -1)
return js_nan();
if (number.as_double() == 1)
return Value(0);
return Value(::acos(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::acosh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() < 1)
return js_nan();
return Value(::acosh(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::asin)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
return number;
return Value(::asin(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::asinh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
return Value(::asinh(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::atan)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan() || number.is_positive_zero() || number.is_negative_zero())
return number;
if (number.is_positive_infinity())
return Value(M_PI_2);
if (number.is_negative_infinity())
return Value(-M_PI_2);
return Value(::atan(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::atanh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() > 1 || number.as_double() < -1)
return js_nan();
return Value(::atanh(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::log1p)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() < -1)
return js_nan();
return Value(::log1p(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::cbrt)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
return Value(::cbrt(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::atan2)
{
auto y = vm.argument(0).to_number(global_object), x = vm.argument(1).to_number(global_object);
auto pi_4 = M_PI_2 / 2;
auto three_pi_4 = pi_4 + M_PI_2;
if (vm.exception())
return {};
if (x.is_positive_zero()) {
if (y.is_positive_zero() || y.is_negative_zero())
return y;
else
return (y.as_double() > 0) ? Value(M_PI_2) : Value(-M_PI_2);
}
if (x.is_negative_zero()) {
if (y.is_positive_zero())
return Value(M_PI);
else if (y.is_negative_zero())
return Value(-M_PI);
else
return (y.as_double() > 0) ? Value(M_PI_2) : Value(-M_PI_2);
}
if (x.is_positive_infinity()) {
if (y.is_infinity())
return (y.is_positive_infinity()) ? Value(pi_4) : Value(-pi_4);
else
return (y.as_double() > 0) ? Value(+0.0) : Value(-0.0);
}
if (x.is_negative_infinity()) {
if (y.is_infinity())
return (y.is_positive_infinity()) ? Value(three_pi_4) : Value(-three_pi_4);
else
return (y.as_double() > 0) ? Value(M_PI) : Value(-M_PI);
}
if (y.is_infinity())
return (y.is_positive_infinity()) ? Value(M_PI_2) : Value(-M_PI_2);
if (y.is_positive_zero())
return (x.as_double() > 0) ? Value(+0.0) : Value(M_PI);
if (y.is_negative_zero())
return (x.as_double() > 0) ? Value(-0.0) : Value(-M_PI);
return Value(::atan2(y.as_double(), x.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::fround)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value((float)number.as_double());
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::hypot)
{
if (!vm.argument_count())
return Value(0);
auto hypot = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
hypot = Value(hypot.as_double() * hypot.as_double());
for (size_t i = 1; i < vm.argument_count(); ++i) {
auto cur = vm.argument(i).to_number(global_object);
if (vm.exception())
return {};
hypot = Value(hypot.as_double() + cur.as_double() * cur.as_double());
}
return Value(::sqrt(hypot.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::log)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() < 0)
return js_nan();
return Value(::log(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::log2)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() < 0)
return js_nan();
return Value(::log2(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::log10)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.as_double() < 0)
return js_nan();
return Value(::log10(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::sinh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::sinh(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::cosh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
return Value(::cosh(number.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::tanh)
{
auto number = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (number.is_nan())
return js_nan();
if (number.is_positive_infinity())
return Value(1);
if (number.is_negative_infinity())
return Value(-1);
return Value(::tanh(number.as_double()));
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class MathObject final : public Object {
JS_OBJECT(MathObject, Object);
public:
explicit MathObject(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~MathObject() override;
private:
JS_DECLARE_NATIVE_FUNCTION(abs);
JS_DECLARE_NATIVE_FUNCTION(random);
JS_DECLARE_NATIVE_FUNCTION(sqrt);
JS_DECLARE_NATIVE_FUNCTION(floor);
JS_DECLARE_NATIVE_FUNCTION(ceil);
JS_DECLARE_NATIVE_FUNCTION(round);
JS_DECLARE_NATIVE_FUNCTION(max);
JS_DECLARE_NATIVE_FUNCTION(min);
JS_DECLARE_NATIVE_FUNCTION(trunc);
JS_DECLARE_NATIVE_FUNCTION(sin);
JS_DECLARE_NATIVE_FUNCTION(cos);
JS_DECLARE_NATIVE_FUNCTION(tan);
JS_DECLARE_NATIVE_FUNCTION(pow);
JS_DECLARE_NATIVE_FUNCTION(exp);
JS_DECLARE_NATIVE_FUNCTION(expm1);
JS_DECLARE_NATIVE_FUNCTION(sign);
JS_DECLARE_NATIVE_FUNCTION(clz32);
JS_DECLARE_NATIVE_FUNCTION(acos);
JS_DECLARE_NATIVE_FUNCTION(acosh);
JS_DECLARE_NATIVE_FUNCTION(asin);
JS_DECLARE_NATIVE_FUNCTION(asinh);
JS_DECLARE_NATIVE_FUNCTION(atan);
JS_DECLARE_NATIVE_FUNCTION(atanh);
JS_DECLARE_NATIVE_FUNCTION(log1p);
JS_DECLARE_NATIVE_FUNCTION(cbrt);
JS_DECLARE_NATIVE_FUNCTION(atan2);
JS_DECLARE_NATIVE_FUNCTION(fround);
JS_DECLARE_NATIVE_FUNCTION(hypot);
JS_DECLARE_NATIVE_FUNCTION(log);
JS_DECLARE_NATIVE_FUNCTION(log2);
JS_DECLARE_NATIVE_FUNCTION(log10);
JS_DECLARE_NATIVE_FUNCTION(sinh);
JS_DECLARE_NATIVE_FUNCTION(cosh);
JS_DECLARE_NATIVE_FUNCTION(tanh);
};
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/LexicalEnvironment.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
NativeFunction* NativeFunction::create(GlobalObject& global_object, const FlyString& name, AK::Function<Value(VM&, GlobalObject&)> function)
{
return global_object.heap().allocate<NativeFunction>(global_object, name, move(function), *global_object.function_prototype());
}
NativeFunction::NativeFunction(Object& prototype)
: Function(prototype)
{
}
NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(VM&, GlobalObject&)> native_function, Object& prototype)
: Function(prototype)
, m_name(name)
, m_native_function(move(native_function))
{
}
NativeFunction::NativeFunction(const FlyString& name, Object& prototype)
: Function(prototype)
, m_name(name)
{
}
NativeFunction::~NativeFunction()
{
}
Value NativeFunction::call()
{
return m_native_function(vm(), global_object());
}
Value NativeFunction::construct(Function&)
{
return {};
}
LexicalEnvironment* NativeFunction::create_environment()
{
return heap().allocate<LexicalEnvironment>(global_object(), LexicalEnvironment::EnvironmentRecordType::Function);
}
bool NativeFunction::is_strict_mode() const
{
return vm().in_strict_mode();
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/Function.h>
#include <LibJS/Runtime/Function.h>
namespace JS {
class NativeFunction : public Function {
JS_OBJECT(NativeFunction, Function);
public:
static NativeFunction* create(GlobalObject&, const FlyString& name, AK::Function<Value(VM&, GlobalObject&)>);
explicit NativeFunction(const FlyString& name, AK::Function<Value(VM&, GlobalObject&)>, Object& prototype);
virtual void initialize(GlobalObject&) override { }
virtual ~NativeFunction() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
virtual const FlyString& name() const override { return m_name; };
virtual bool has_constructor() const { return false; }
virtual bool is_strict_mode() const override;
protected:
NativeFunction(const FlyString& name, Object& prototype);
explicit NativeFunction(Object& prototype);
private:
virtual LexicalEnvironment* create_environment() override final;
FlyString m_name;
AK::Function<Value(VM&, GlobalObject&)> m_native_function;
};
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Runtime/NativeProperty.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
NativeProperty::NativeProperty(AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter)
: m_getter(move(getter))
, m_setter(move(setter))
{
}
NativeProperty::~NativeProperty()
{
}
Value NativeProperty::get(VM& vm, GlobalObject& global_object) const
{
if (!m_getter)
return js_undefined();
return m_getter(vm, global_object);
}
void NativeProperty::set(VM& vm, GlobalObject& global_object, Value value)
{
if (!m_setter)
return;
m_setter(vm, global_object, move(value));
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/Function.h>
#include <LibJS/Runtime/Object.h>
namespace JS {
class NativeProperty final : public Cell {
public:
NativeProperty(AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter);
virtual ~NativeProperty() override;
Value get(VM&, GlobalObject&) const;
void set(VM&, GlobalObject&, Value);
private:
virtual const char* class_name() const override { return "NativeProperty"; }
AK::Function<Value(VM&, GlobalObject&)> m_getter;
AK::Function<void(VM&, GlobalObject&, Value)> m_setter;
};
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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.
*/
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberConstructor.h>
#include <LibJS/Runtime/NumberObject.h>
#include <math.h>
#ifdef __clang__
# define EPSILON_VALUE pow(2, -52)
# define MAX_SAFE_INTEGER_VALUE pow(2, 53) - 1
# define MIN_SAFE_INTEGER_VALUE -(pow(2, 53) - 1)
#else
constexpr const double EPSILON_VALUE { __builtin_pow(2, -52) };
constexpr const double MAX_SAFE_INTEGER_VALUE { __builtin_pow(2, 53) - 1 };
constexpr const double MIN_SAFE_INTEGER_VALUE { -(__builtin_pow(2, 53) - 1) };
#endif
namespace JS {
NumberConstructor::NumberConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Number, *global_object.function_prototype())
{
}
void NumberConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.isFinite, is_finite, 1, attr);
define_native_function(vm.names.isInteger, is_integer, 1, attr);
define_native_function(vm.names.isNaN, is_nan, 1, attr);
define_native_function(vm.names.isSafeInteger, is_safe_integer, 1, attr);
define_property(vm.names.parseFloat, global_object.get(vm.names.parseFloat));
define_property(vm.names.prototype, global_object.number_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
define_property(vm.names.EPSILON, Value(EPSILON_VALUE), 0);
define_property(vm.names.MAX_SAFE_INTEGER, Value(MAX_SAFE_INTEGER_VALUE), 0);
define_property(vm.names.MIN_SAFE_INTEGER, Value(MIN_SAFE_INTEGER_VALUE), 0);
define_property(vm.names.NEGATIVE_INFINITY, js_negative_infinity(), 0);
define_property(vm.names.POSITIVE_INFINITY, js_infinity(), 0);
define_property(vm.names.NaN, js_nan(), 0);
}
NumberConstructor::~NumberConstructor()
{
}
Value NumberConstructor::call()
{
if (!vm().argument_count())
return Value(0);
return vm().argument(0).to_number(global_object());
}
Value NumberConstructor::construct(Function&)
{
double number = 0;
if (vm().argument_count()) {
number = vm().argument(0).to_double(global_object());
if (vm().exception())
return {};
}
return NumberObject::create(global_object(), number);
}
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_finite)
{
return Value(vm.argument(0).is_finite_number());
}
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_integer)
{
return Value(vm.argument(0).is_integer());
}
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_nan)
{
return Value(vm.argument(0).is_nan());
}
JS_DEFINE_NATIVE_FUNCTION(NumberConstructor::is_safe_integer)
{
if (!vm.argument(0).is_number())
return Value(false);
auto value = vm.argument(0).as_double();
return Value((int64_t)value == value && value >= MIN_SAFE_INTEGER_VALUE && value <= MAX_SAFE_INTEGER_VALUE);
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class NumberConstructor final : public NativeFunction {
JS_OBJECT(NumberConstructor, NativeFunction);
public:
explicit NumberConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~NumberConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(is_finite);
JS_DECLARE_NATIVE_FUNCTION(is_integer);
JS_DECLARE_NATIVE_FUNCTION(is_nan);
JS_DECLARE_NATIVE_FUNCTION(is_safe_integer);
};
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/NumberPrototype.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
NumberObject* NumberObject::create(GlobalObject& global_object, double value)
{
return global_object.heap().allocate<NumberObject>(global_object, value, *global_object.number_prototype());
}
NumberObject::NumberObject(double value, Object& prototype)
: Object(prototype)
, m_value(value)
{
}
NumberObject::~NumberObject()
{
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class NumberObject : public Object {
JS_OBJECT(NumberObject, Object);
public:
static NumberObject* create(GlobalObject&, double);
NumberObject(double, Object& prototype);
virtual ~NumberObject() override;
virtual Value value_of() const override { return Value(m_value); }
double number() const { return m_value; }
private:
double m_value { 0 };
};
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/NumberPrototype.h>
namespace JS {
static const u8 max_precision_for_radix[37] = {
// clang-format off
0, 0, 52, 32, 26, 22, 20, 18, 17, 16,
15, 15, 14, 14, 13, 13, 13, 12, 12, 12,
12, 11, 11, 11, 11, 11, 11, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10,
// clang-format on
};
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
NumberPrototype::NumberPrototype(GlobalObject& global_object)
: NumberObject(0, *global_object.object_prototype())
{
}
void NumberPrototype::initialize(GlobalObject& object)
{
auto& vm = this->vm();
Object::initialize(object);
define_native_function(vm.names.toString, to_string, 1, Attribute::Configurable | Attribute::Writable);
}
NumberPrototype::~NumberPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_string)
{
Value number_value;
auto this_value = vm.this_value(global_object);
if (this_value.is_number()) {
number_value = this_value;
} else if (this_value.is_object() && is<NumberObject>(this_value.as_object())) {
number_value = static_cast<NumberObject&>(this_value.as_object()).value_of();
} else {
vm.throw_exception<TypeError>(global_object, ErrorType::NumberIncompatibleThis, "toString");
return {};
}
int radix;
auto argument = vm.argument(0);
if (argument.is_undefined()) {
radix = 10;
} else {
radix = argument.to_i32(global_object);
}
if (vm.exception() || radix < 2 || radix > 36) {
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidRadix);
return {};
}
if (number_value.is_positive_infinity())
return js_string(vm, "Infinity");
if (number_value.is_negative_infinity())
return js_string(vm, "-Infinity");
if (number_value.is_nan())
return js_string(vm, "NaN");
if (number_value.is_positive_zero() || number_value.is_negative_zero())
return js_string(vm, "0");
double number = number_value.as_double();
bool negative = number < 0;
if (negative)
number *= -1;
int int_part = floor(number);
double decimal_part = number - int_part;
Vector<char> backwards_characters;
if (int_part == 0) {
backwards_characters.append('0');
} else {
while (int_part > 0) {
backwards_characters.append(digits[int_part % radix]);
int_part /= radix;
}
}
Vector<char> characters;
if (negative)
characters.append('-');
// Reverse characters;
for (ssize_t i = backwards_characters.size() - 1; i >= 0; --i) {
characters.append(backwards_characters[i]);
}
// decimal part
if (decimal_part != 0.0) {
characters.append('.');
int precision = max_precision_for_radix[radix];
for (int i = 0; i < precision; ++i) {
decimal_part *= radix;
int integral = floor(decimal_part);
characters.append(digits[integral]);
decimal_part -= integral;
}
while (characters.last() == '0')
characters.take_last();
}
return js_string(vm, String(characters.data(), characters.size()));
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/NumberObject.h>
namespace JS {
class NumberPrototype final : public NumberObject {
JS_OBJECT(NumberPrototype, NumberObject);
public:
explicit NumberPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~NumberPrototype() override;
JS_DECLARE_NATIVE_FUNCTION(to_string);
};
}

View file

@ -0,0 +1,927 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/String.h>
#include <AK/TemporaryChange.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/NativeProperty.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/Shape.h>
#include <LibJS/Runtime/StringObject.h>
#include <LibJS/Runtime/Value.h>
//#define OBJECT_DEBUG
namespace JS {
PropertyDescriptor PropertyDescriptor::from_dictionary(VM& vm, const Object& object)
{
PropertyAttributes attributes;
if (object.has_property(vm.names.configurable)) {
attributes.set_has_configurable();
if (object.get(vm.names.configurable).value_or(Value(false)).to_boolean())
attributes.set_configurable();
if (vm.exception())
return {};
}
if (object.has_property(vm.names.enumerable)) {
attributes.set_has_enumerable();
if (object.get(vm.names.enumerable).value_or(Value(false)).to_boolean())
attributes.set_enumerable();
if (vm.exception())
return {};
}
if (object.has_property(vm.names.writable)) {
attributes.set_has_writable();
if (object.get(vm.names.writable).value_or(Value(false)).to_boolean())
attributes.set_writable();
if (vm.exception())
return {};
}
PropertyDescriptor descriptor { attributes, object.get(vm.names.value), nullptr, nullptr };
if (vm.exception())
return {};
auto getter = object.get(vm.names.get);
if (vm.exception())
return {};
if (getter.is_function())
descriptor.getter = &getter.as_function();
auto setter = object.get(vm.names.set);
if (vm.exception())
return {};
if (setter.is_function())
descriptor.setter = &setter.as_function();
return descriptor;
}
Object* Object::create_empty(GlobalObject& global_object)
{
return global_object.heap().allocate<Object>(global_object, *global_object.new_object_shape());
}
Object::Object(GlobalObjectTag)
{
// This is the global object
m_shape = heap().allocate_without_global_object<Shape>(*this);
}
Object::Object(ConstructWithoutPrototypeTag, GlobalObject& global_object)
{
m_shape = heap().allocate_without_global_object<Shape>(global_object);
}
Object::Object(Object& prototype)
{
m_shape = prototype.global_object().empty_object_shape();
set_prototype(&prototype);
}
Object::Object(Shape& shape)
: m_shape(&shape)
{
m_storage.resize(shape.property_count());
}
void Object::initialize(GlobalObject&)
{
}
Object::~Object()
{
}
Object* Object::prototype()
{
return shape().prototype();
}
const Object* Object::prototype() const
{
return shape().prototype();
}
bool Object::set_prototype(Object* new_prototype)
{
if (prototype() == new_prototype)
return true;
if (!m_is_extensible)
return false;
if (shape().is_unique()) {
shape().set_prototype_without_transition(new_prototype);
return true;
}
m_shape = m_shape->create_prototype_transition(new_prototype);
return true;
}
bool Object::has_prototype(const Object* prototype) const
{
for (auto* object = this->prototype(); object; object = object->prototype()) {
if (vm().exception())
return false;
if (object == prototype)
return true;
}
return false;
}
bool Object::prevent_extensions()
{
m_is_extensible = false;
return true;
}
Value Object::get_own_property(const PropertyName& property_name, Value receiver) const
{
ASSERT(property_name.is_valid());
ASSERT(!receiver.is_empty());
Value value_here;
if (property_name.is_number()) {
auto existing_property = m_indexed_properties.get(nullptr, property_name.as_number(), false);
if (!existing_property.has_value())
return {};
value_here = existing_property.value().value.value_or(js_undefined());
} else {
auto metadata = shape().lookup(property_name.to_string_or_symbol());
if (!metadata.has_value())
return {};
value_here = m_storage[metadata.value().offset].value_or(js_undefined());
}
ASSERT(!value_here.is_empty());
if (value_here.is_accessor())
return value_here.as_accessor().call_getter(receiver);
if (value_here.is_native_property())
return call_native_property_getter(value_here.as_native_property(), receiver);
return value_here;
}
Value Object::get_own_properties(const Object& this_object, PropertyKind kind, bool only_enumerable_properties, GetOwnPropertyReturnType return_type) const
{
auto* properties_array = Array::create(global_object());
// FIXME: Support generic iterables
if (is<StringObject>(this_object)) {
auto str = static_cast<const StringObject&>(this_object).primitive_string().string();
for (size_t i = 0; i < str.length(); ++i) {
if (kind == PropertyKind::Key) {
properties_array->define_property(i, js_string(vm(), String::number(i)));
} else if (kind == PropertyKind::Value) {
properties_array->define_property(i, js_string(vm(), String::formatted("{:c}", str[i])));
} else {
auto* entry_array = Array::create(global_object());
entry_array->define_property(0, js_string(vm(), String::number(i)));
entry_array->define_property(1, js_string(vm(), String::formatted("{:c}", str[i])));
properties_array->define_property(i, entry_array);
}
if (vm().exception())
return {};
}
return properties_array;
}
size_t property_index = 0;
for (auto& entry : m_indexed_properties) {
auto value_and_attributes = entry.value_and_attributes(const_cast<Object*>(&this_object));
if (only_enumerable_properties && !value_and_attributes.attributes.is_enumerable())
continue;
if (kind == PropertyKind::Key) {
properties_array->define_property(property_index, js_string(vm(), String::number(entry.index())));
} else if (kind == PropertyKind::Value) {
properties_array->define_property(property_index, value_and_attributes.value);
} else {
auto* entry_array = Array::create(global_object());
entry_array->define_property(0, js_string(vm(), String::number(entry.index())));
entry_array->define_property(1, value_and_attributes.value);
properties_array->define_property(property_index, entry_array);
}
if (vm().exception())
return {};
++property_index;
}
for (auto& it : this_object.shape().property_table_ordered()) {
if (only_enumerable_properties && !it.value.attributes.is_enumerable())
continue;
if (return_type == GetOwnPropertyReturnType::StringOnly && it.key.is_symbol())
continue;
if (return_type == GetOwnPropertyReturnType::SymbolOnly && it.key.is_string())
continue;
if (kind == PropertyKind::Key) {
properties_array->define_property(property_index, it.key.to_value(vm()));
} else if (kind == PropertyKind::Value) {
properties_array->define_property(property_index, this_object.get(it.key));
} else {
auto* entry_array = Array::create(global_object());
entry_array->define_property(0, it.key.to_value(vm()));
entry_array->define_property(1, this_object.get(it.key));
properties_array->define_property(property_index, entry_array);
}
if (vm().exception())
return {};
++property_index;
}
return properties_array;
}
Optional<PropertyDescriptor> Object::get_own_property_descriptor(const PropertyName& property_name) const
{
ASSERT(property_name.is_valid());
Value value;
PropertyAttributes attributes;
if (property_name.is_number()) {
auto existing_value = m_indexed_properties.get(nullptr, property_name.as_number(), false);
if (!existing_value.has_value())
return {};
value = existing_value.value().value;
attributes = existing_value.value().attributes;
attributes = default_attributes;
} else {
auto metadata = shape().lookup(property_name.to_string_or_symbol());
if (!metadata.has_value())
return {};
value = m_storage[metadata.value().offset];
if (vm().exception())
return {};
attributes = metadata.value().attributes;
}
PropertyDescriptor descriptor { attributes, {}, nullptr, nullptr };
if (value.is_native_property()) {
auto result = call_native_property_getter(value.as_native_property(), const_cast<Object*>(this));
descriptor.value = result.value_or(js_undefined());
} else if (value.is_accessor()) {
auto& pair = value.as_accessor();
if (pair.getter())
descriptor.getter = pair.getter();
if (pair.setter())
descriptor.setter = pair.setter();
} else {
descriptor.value = value.value_or(js_undefined());
}
return descriptor;
}
Value Object::get_own_property_descriptor_object(const PropertyName& property_name) const
{
ASSERT(property_name.is_valid());
auto& vm = this->vm();
auto descriptor_opt = get_own_property_descriptor(property_name);
if (!descriptor_opt.has_value())
return js_undefined();
auto descriptor = descriptor_opt.value();
auto* descriptor_object = Object::create_empty(global_object());
descriptor_object->define_property(vm.names.enumerable, Value(descriptor.attributes.is_enumerable()));
if (vm.exception())
return {};
descriptor_object->define_property(vm.names.configurable, Value(descriptor.attributes.is_configurable()));
if (vm.exception())
return {};
if (descriptor.is_data_descriptor()) {
descriptor_object->define_property(vm.names.value, descriptor.value.value_or(js_undefined()));
if (vm.exception())
return {};
descriptor_object->define_property(vm.names.writable, Value(descriptor.attributes.is_writable()));
if (vm.exception())
return {};
} else if (descriptor.is_accessor_descriptor()) {
if (descriptor.getter) {
descriptor_object->define_property(vm.names.get, Value(descriptor.getter));
if (vm.exception())
return {};
}
if (descriptor.setter) {
descriptor_object->define_property(vm.names.set, Value(descriptor.setter));
if (vm.exception())
return {};
}
}
return descriptor_object;
}
void Object::set_shape(Shape& new_shape)
{
m_storage.resize(new_shape.property_count());
m_shape = &new_shape;
}
bool Object::define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions)
{
auto& vm = this->vm();
bool is_accessor_property = descriptor.has_property(vm.names.get) || descriptor.has_property(vm.names.set);
PropertyAttributes attributes;
if (descriptor.has_property(vm.names.configurable)) {
attributes.set_has_configurable();
if (descriptor.get(vm.names.configurable).value_or(Value(false)).to_boolean())
attributes.set_configurable();
if (vm.exception())
return false;
}
if (descriptor.has_property(vm.names.enumerable)) {
attributes.set_has_enumerable();
if (descriptor.get(vm.names.enumerable).value_or(Value(false)).to_boolean())
attributes.set_enumerable();
if (vm.exception())
return false;
}
if (is_accessor_property) {
if (descriptor.has_property(vm.names.value) || descriptor.has_property(vm.names.writable)) {
if (throw_exceptions)
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorValueOrWritable);
return false;
}
auto getter = descriptor.get(vm.names.get).value_or(js_undefined());
if (vm.exception())
return {};
auto setter = descriptor.get(vm.names.set).value_or(js_undefined());
if (vm.exception())
return {};
Function* getter_function { nullptr };
Function* setter_function { nullptr };
if (getter.is_function()) {
getter_function = &getter.as_function();
} else if (!getter.is_undefined()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "get");
return false;
}
if (setter.is_function()) {
setter_function = &setter.as_function();
} else if (!setter.is_undefined()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::AccessorBadField, "set");
return false;
}
#ifdef OBJECT_DEBUG
dbgln("Defining new property {} with accessor descriptor {{ attributes={}, getter={}, setter={} }}", property_name.to_display_string(), attributes, getter, setter);
#endif
return define_property(property_name, Accessor::create(vm, getter_function, setter_function), attributes, throw_exceptions);
}
auto value = descriptor.get(vm.names.value);
if (vm.exception())
return {};
if (descriptor.has_property(vm.names.writable)) {
attributes.set_has_writable();
if (descriptor.get(vm.names.writable).value_or(Value(false)).to_boolean())
attributes.set_writable();
if (vm.exception())
return false;
}
if (vm.exception())
return {};
#ifdef OBJECT_DEBUG
dbgln("Defining new property {} with data descriptor {{ attributes={}, value={} }}", property_name.to_display_string(), attributes, value);
#endif
return define_property(property_name, value, attributes, throw_exceptions);
}
bool Object::define_property_without_transition(const PropertyName& property_name, Value value, PropertyAttributes attributes, bool throw_exceptions)
{
TemporaryChange change(m_transitions_enabled, false);
return define_property(property_name, value, attributes, throw_exceptions);
}
bool Object::define_property(const PropertyName& property_name, Value value, PropertyAttributes attributes, bool throw_exceptions)
{
ASSERT(property_name.is_valid());
if (property_name.is_number())
return put_own_property_by_index(*this, property_name.as_number(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
if (property_name.is_string()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return put_own_property_by_index(*this, property_index, value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
}
return put_own_property(*this, property_name.to_string_or_symbol(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
}
bool Object::define_accessor(const PropertyName& property_name, Function& getter_or_setter, bool is_getter, PropertyAttributes attributes, bool throw_exceptions)
{
ASSERT(property_name.is_valid());
Accessor* accessor { nullptr };
auto property_metadata = shape().lookup(property_name.to_string_or_symbol());
if (property_metadata.has_value()) {
auto existing_property = get_direct(property_metadata.value().offset);
if (existing_property.is_accessor())
accessor = &existing_property.as_accessor();
}
if (!accessor) {
accessor = Accessor::create(vm(), nullptr, nullptr);
bool definition_success = define_property(property_name, accessor, attributes, throw_exceptions);
if (vm().exception())
return {};
if (!definition_success)
return false;
}
if (is_getter)
accessor->set_getter(&getter_or_setter);
else
accessor->set_setter(&getter_or_setter);
return true;
}
bool Object::put_own_property(Object& this_object, const StringOrSymbol& property_name, Value value, PropertyAttributes attributes, PutOwnPropertyMode mode, bool throw_exceptions)
{
ASSERT(!(mode == PutOwnPropertyMode::Put && value.is_accessor()));
if (value.is_accessor()) {
auto& accessor = value.as_accessor();
if (accessor.getter())
attributes.set_has_getter();
if (accessor.setter())
attributes.set_has_setter();
}
// NOTE: We disable transitions during initialize(), this makes building common runtime objects significantly faster.
// Transitions are primarily interesting when scripts add properties to objects.
if (!m_transitions_enabled && !m_shape->is_unique()) {
m_shape->add_property_without_transition(property_name, attributes);
m_storage.resize(m_shape->property_count());
m_storage[m_shape->property_count() - 1] = value;
return true;
}
auto metadata = shape().lookup(property_name);
bool new_property = !metadata.has_value();
if (!is_extensible() && new_property) {
#ifdef OBJECT_DEBUG
dbgln("Disallow define_property of non-extensible object");
#endif
if (throw_exceptions && vm().in_strict_mode())
vm().throw_exception<TypeError>(global_object(), ErrorType::NonExtensibleDefine, property_name.to_display_string());
return false;
}
if (new_property) {
if (!m_shape->is_unique() && shape().property_count() > 100) {
// If you add more than 100 properties to an object, let's stop doing
// transitions to avoid filling up the heap with shapes.
ensure_shape_is_unique();
}
if (m_shape->is_unique()) {
m_shape->add_property_to_unique_shape(property_name, attributes);
m_storage.resize(m_shape->property_count());
} else if (m_transitions_enabled) {
set_shape(*m_shape->create_put_transition(property_name, attributes));
} else {
m_shape->add_property_without_transition(property_name, attributes);
m_storage.resize(m_shape->property_count());
}
metadata = shape().lookup(property_name);
ASSERT(metadata.has_value());
}
if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !metadata.value().attributes.is_configurable() && attributes != metadata.value().attributes) {
#ifdef OBJECT_DEBUG
dbgln("Disallow reconfig of non-configurable property");
#endif
if (throw_exceptions)
vm().throw_exception<TypeError>(global_object(), ErrorType::DescChangeNonConfigurable, property_name.to_display_string());
return false;
}
if (mode == PutOwnPropertyMode::DefineProperty && attributes != metadata.value().attributes) {
if (m_shape->is_unique()) {
m_shape->reconfigure_property_in_unique_shape(property_name, attributes);
} else {
set_shape(*m_shape->create_configure_transition(property_name, attributes));
}
metadata = shape().lookup(property_name);
#ifdef OBJECT_DEBUG
dbgln("Reconfigured property {}, new shape says offset is {} and my storage capacity is {}", property_name.to_display_string(), metadata.value().offset, m_storage.size());
#endif
}
auto value_here = m_storage[metadata.value().offset];
if (!new_property && mode == PutOwnPropertyMode::Put && !value_here.is_accessor() && !metadata.value().attributes.is_writable()) {
#ifdef OBJECT_DEBUG
dbgln("Disallow write to non-writable property");
#endif
return false;
}
if (value.is_empty())
return true;
if (value_here.is_native_property()) {
call_native_property_setter(value_here.as_native_property(), &this_object, value);
} else {
m_storage[metadata.value().offset] = value;
}
return true;
}
bool Object::put_own_property_by_index(Object& this_object, u32 property_index, Value value, PropertyAttributes attributes, PutOwnPropertyMode mode, bool throw_exceptions)
{
ASSERT(!(mode == PutOwnPropertyMode::Put && value.is_accessor()));
auto existing_property = m_indexed_properties.get(nullptr, property_index, false);
auto new_property = !existing_property.has_value();
if (!is_extensible() && new_property) {
#ifdef OBJECT_DEBUG
dbgln("Disallow define_property of non-extensible object");
#endif
if (throw_exceptions && vm().in_strict_mode())
vm().throw_exception<TypeError>(global_object(), ErrorType::NonExtensibleDefine, property_index);
return false;
}
if (value.is_accessor()) {
auto& accessor = value.as_accessor();
if (accessor.getter())
attributes.set_has_getter();
if (accessor.setter())
attributes.set_has_setter();
}
PropertyAttributes existing_attributes = new_property ? 0 : existing_property.value().attributes;
if (!new_property && mode == PutOwnPropertyMode::DefineProperty && !existing_attributes.is_configurable() && attributes != existing_attributes) {
#ifdef OBJECT_DEBUG
dbgln("Disallow reconfig of non-configurable property");
#endif
if (throw_exceptions)
vm().throw_exception<TypeError>(global_object(), ErrorType::DescChangeNonConfigurable, property_index);
return false;
}
auto value_here = new_property ? Value() : existing_property.value().value;
if (!new_property && mode == PutOwnPropertyMode::Put && !value_here.is_accessor() && !existing_attributes.is_writable()) {
#ifdef OBJECT_DEBUG
dbgln("Disallow write to non-writable property");
#endif
return false;
}
if (value.is_empty())
return true;
if (value_here.is_native_property()) {
call_native_property_setter(value_here.as_native_property(), &this_object, value);
} else {
m_indexed_properties.put(&this_object, property_index, value, attributes, mode == PutOwnPropertyMode::Put);
}
return true;
}
Value Object::delete_property(const PropertyName& property_name)
{
ASSERT(property_name.is_valid());
if (property_name.is_number())
return Value(m_indexed_properties.remove(property_name.as_number()));
if (property_name.is_string()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return Value(m_indexed_properties.remove(property_index));
}
auto metadata = shape().lookup(property_name.to_string_or_symbol());
if (!metadata.has_value())
return Value(true);
if (!metadata.value().attributes.is_configurable())
return Value(false);
size_t deleted_offset = metadata.value().offset;
ensure_shape_is_unique();
shape().remove_property_from_unique_shape(property_name.to_string_or_symbol(), deleted_offset);
m_storage.remove(deleted_offset);
return Value(true);
}
void Object::ensure_shape_is_unique()
{
if (shape().is_unique())
return;
m_shape = m_shape->create_unique_clone();
}
Value Object::get_by_index(u32 property_index) const
{
const Object* object = this;
while (object) {
if (is<StringObject>(*this)) {
auto& string = static_cast<const StringObject*>(this)->primitive_string().string();
if (property_index < string.length())
return js_string(heap(), string.substring(property_index, 1));
return js_undefined();
}
if (static_cast<size_t>(property_index) < object->m_indexed_properties.array_like_size()) {
auto result = object->m_indexed_properties.get(const_cast<Object*>(this), property_index);
if (vm().exception())
return {};
if (result.has_value() && !result.value().value.is_empty())
return result.value().value;
return {};
}
object = object->prototype();
if (vm().exception())
return {};
}
return {};
}
Value Object::get(const PropertyName& property_name, Value receiver) const
{
ASSERT(property_name.is_valid());
if (property_name.is_number())
return get_by_index(property_name.as_number());
if (property_name.is_string()) {
auto property_string = property_name.to_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
return get_by_index(property_index);
}
const Object* object = this;
while (object) {
if (receiver.is_empty())
receiver = Value(const_cast<Object*>(this));
auto value = object->get_own_property(property_name, receiver);
if (vm().exception())
return {};
if (!value.is_empty())
return value;
object = object->prototype();
if (vm().exception())
return {};
}
return {};
}
bool Object::put_by_index(u32 property_index, Value value)
{
ASSERT(!value.is_empty());
// If there's a setter in the prototype chain, we go to the setter.
// Otherwise, it goes in the own property storage.
Object* object = this;
while (object) {
auto existing_value = object->m_indexed_properties.get(nullptr, property_index, false);
if (existing_value.has_value()) {
auto value_here = existing_value.value();
if (value_here.value.is_accessor()) {
value_here.value.as_accessor().call_setter(object, value);
return true;
}
if (value_here.value.is_native_property()) {
// FIXME: Why doesn't put_by_index() receive the receiver value from put()?!
auto receiver = this;
call_native_property_setter(value_here.value.as_native_property(), receiver, value);
return true;
}
}
object = object->prototype();
if (vm().exception())
return {};
}
return put_own_property_by_index(*this, property_index, value, default_attributes, PutOwnPropertyMode::Put);
}
bool Object::put(const PropertyName& property_name, Value value, Value receiver)
{
ASSERT(property_name.is_valid());
if (property_name.is_number())
return put_by_index(property_name.as_number(), value);
ASSERT(!value.is_empty());
if (property_name.is_string()) {
auto& property_string = property_name.as_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
return put_by_index(property_index, value);
}
auto string_or_symbol = property_name.to_string_or_symbol();
if (receiver.is_empty())
receiver = Value(this);
// If there's a setter in the prototype chain, we go to the setter.
// Otherwise, it goes in the own property storage.
Object* object = this;
while (object) {
auto metadata = object->shape().lookup(string_or_symbol);
if (metadata.has_value()) {
auto value_here = object->m_storage[metadata.value().offset];
if (value_here.is_accessor()) {
value_here.as_accessor().call_setter(receiver, value);
return true;
}
if (value_here.is_native_property()) {
call_native_property_setter(value_here.as_native_property(), receiver, value);
return true;
}
}
object = object->prototype();
if (vm().exception())
return false;
}
return put_own_property(*this, string_or_symbol, value, default_attributes, PutOwnPropertyMode::Put);
}
bool Object::define_native_function(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
{
auto& vm = this->vm();
String function_name;
if (property_name.is_string()) {
function_name = property_name.as_string();
} else {
function_name = String::formatted("[{}]", property_name.as_symbol()->description());
}
auto* function = NativeFunction::create(global_object(), function_name, move(native_function));
function->define_property_without_transition(vm.names.length, Value(length), Attribute::Configurable);
if (vm.exception())
return {};
function->define_property_without_transition(vm.names.name, js_string(vm.heap(), function_name), Attribute::Configurable);
if (vm.exception())
return {};
return define_property(property_name, function, attribute);
}
bool Object::define_native_property(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attribute)
{
return define_property(property_name, heap().allocate_without_global_object<NativeProperty>(move(getter), move(setter)), attribute);
}
void Object::visit_edges(Cell::Visitor& visitor)
{
Cell::visit_edges(visitor);
visitor.visit(m_shape);
for (auto& value : m_storage)
visitor.visit(value);
m_indexed_properties.for_each_value([&visitor](auto& value) {
visitor.visit(value);
});
}
bool Object::has_property(const PropertyName& property_name) const
{
const Object* object = this;
while (object) {
if (object->has_own_property(property_name))
return true;
object = object->prototype();
if (vm().exception())
return false;
}
return false;
}
bool Object::has_own_property(const PropertyName& property_name) const
{
ASSERT(property_name.is_valid());
auto has_indexed_property = [&](u32 index) -> bool {
if (is<StringObject>(*this))
return index < static_cast<const StringObject*>(this)->primitive_string().string().length();
return m_indexed_properties.has_index(index);
};
if (property_name.is_number())
return has_indexed_property(property_name.as_number());
if (property_name.is_string()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return has_indexed_property(property_index);
}
return shape().lookup(property_name.to_string_or_symbol()).has_value();
}
Value Object::ordinary_to_primitive(Value::PreferredType preferred_type) const
{
ASSERT(preferred_type == Value::PreferredType::String || preferred_type == Value::PreferredType::Number);
auto& vm = this->vm();
Vector<FlyString, 2> method_names;
if (preferred_type == Value::PreferredType::String)
method_names = { vm.names.toString, vm.names.valueOf };
else
method_names = { vm.names.valueOf, vm.names.toString };
for (auto& method_name : method_names) {
auto method = get(method_name);
if (vm.exception())
return {};
if (method.is_function()) {
auto result = vm.call(method.as_function(), const_cast<Object*>(this));
if (!result.is_object())
return result;
}
}
vm.throw_exception<TypeError>(global_object(), ErrorType::Convert, "object", preferred_type == Value::PreferredType::String ? "string" : "number");
return {};
}
Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueList> arguments)
{
auto& vm = this->vm();
auto property = get(property_name).value_or(js_undefined());
if (vm.exception())
return {};
if (!property.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, property.to_string_without_side_effects());
return {};
}
return vm.call(property.as_function(), this, move(arguments));
}
Value Object::call_native_property_getter(NativeProperty& property, Value this_value) const
{
auto& vm = this->vm();
CallFrame call_frame;
call_frame.is_strict_mode = vm.in_strict_mode();
call_frame.this_value = this_value;
vm.push_call_frame(call_frame, global_object());
if (vm.exception())
return {};
auto result = property.get(vm, global_object());
vm.pop_call_frame();
return result;
}
void Object::call_native_property_setter(NativeProperty& property, Value this_value, Value setter_value) const
{
auto& vm = this->vm();
CallFrame call_frame;
call_frame.is_strict_mode = vm.in_strict_mode();
call_frame.this_value = this_value;
vm.push_call_frame(call_frame, global_object());
if (vm.exception())
return;
property.set(vm, global_object(), setter_value);
vm.pop_call_frame();
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/HashMap.h>
#include <AK/String.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Cell.h>
#include <LibJS/Runtime/IndexedProperties.h>
#include <LibJS/Runtime/MarkedValueList.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/PropertyName.h>
#include <LibJS/Runtime/Shape.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
#define JS_OBJECT(class_, base_class) \
public: \
using Base = base_class; \
virtual const char* class_name() const override { return #class_; }
struct PropertyDescriptor {
PropertyAttributes attributes;
Value value;
Function* getter { nullptr };
Function* setter { nullptr };
static PropertyDescriptor from_dictionary(VM&, const Object&);
bool is_accessor_descriptor() const { return getter || setter; }
bool is_data_descriptor() const { return !(value.is_empty() && !attributes.has_writable()); }
bool is_generic_descriptor() const { return !is_accessor_descriptor() && !is_data_descriptor(); }
};
class Object : public Cell {
public:
static Object* create_empty(GlobalObject&);
explicit Object(Object& prototype);
explicit Object(Shape&);
virtual void initialize(GlobalObject&) override;
virtual ~Object();
enum class PropertyKind {
Key,
Value,
KeyAndValue,
};
enum class GetOwnPropertyReturnType {
StringOnly,
SymbolOnly,
};
enum class PutOwnPropertyMode {
Put,
DefineProperty,
};
Shape& shape() { return *m_shape; }
const Shape& shape() const { return *m_shape; }
GlobalObject& global_object() const { return *shape().global_object(); }
virtual Value get(const PropertyName&, Value receiver = {}) const;
virtual bool has_property(const PropertyName&) const;
bool has_own_property(const PropertyName&) const;
virtual bool put(const PropertyName&, Value, Value receiver = {});
Value get_own_property(const PropertyName&, Value receiver) const;
Value get_own_properties(const Object& this_object, PropertyKind, bool only_enumerable_properties = false, GetOwnPropertyReturnType = GetOwnPropertyReturnType::StringOnly) const;
virtual Optional<PropertyDescriptor> get_own_property_descriptor(const PropertyName&) const;
Value get_own_property_descriptor_object(const PropertyName&) const;
virtual bool define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions = true);
bool define_property(const PropertyName&, Value value, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true);
bool define_property_without_transition(const PropertyName&, Value value, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true);
bool define_accessor(const PropertyName&, Function& getter_or_setter, bool is_getter, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true);
bool define_native_function(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)>, i32 length = 0, PropertyAttributes attributes = default_attributes);
bool define_native_property(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attributes = default_attributes);
virtual Value delete_property(const PropertyName&);
virtual bool is_array() const { return false; }
virtual bool is_function() const { return false; }
virtual bool is_typed_array() const { return false; }
virtual const char* class_name() const override { return "Object"; }
virtual void visit_edges(Cell::Visitor&) override;
virtual Object* prototype();
virtual const Object* prototype() const;
virtual bool set_prototype(Object* prototype);
bool has_prototype(const Object* prototype) const;
virtual bool is_extensible() const { return m_is_extensible; }
virtual bool prevent_extensions();
virtual Value value_of() const { return Value(const_cast<Object*>(this)); }
virtual Value ordinary_to_primitive(Value::PreferredType preferred_type) const;
Value get_direct(size_t index) const { return m_storage[index]; }
const IndexedProperties& indexed_properties() const { return m_indexed_properties; }
IndexedProperties& indexed_properties() { return m_indexed_properties; }
void set_indexed_property_elements(Vector<Value>&& values) { m_indexed_properties = IndexedProperties(move(values)); }
Value invoke(const StringOrSymbol& property_name, Optional<MarkedValueList> arguments = {});
void ensure_shape_is_unique();
void enable_transitions() { m_transitions_enabled = true; }
void disable_transitions() { m_transitions_enabled = false; }
protected:
enum class GlobalObjectTag { Tag };
enum class ConstructWithoutPrototypeTag { Tag };
explicit Object(GlobalObjectTag);
Object(ConstructWithoutPrototypeTag, GlobalObject&);
virtual Value get_by_index(u32 property_index) const;
virtual bool put_by_index(u32 property_index, Value);
private:
bool put_own_property(Object& this_object, const StringOrSymbol& property_name, Value, PropertyAttributes attributes, PutOwnPropertyMode = PutOwnPropertyMode::Put, bool throw_exceptions = true);
bool put_own_property_by_index(Object& this_object, u32 property_index, Value, PropertyAttributes attributes, PutOwnPropertyMode = PutOwnPropertyMode::Put, bool throw_exceptions = true);
Value call_native_property_getter(NativeProperty& property, Value this_value) const;
void call_native_property_setter(NativeProperty& property, Value this_value, Value) const;
void set_shape(Shape&);
bool m_is_extensible { true };
bool m_transitions_enabled { true };
Shape* m_shape { nullptr };
Vector<Value> m_storage;
IndexedProperties m_indexed_properties;
};
}

View file

@ -0,0 +1,242 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/Function.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ObjectConstructor.h>
#include <LibJS/Runtime/ProxyObject.h>
#include <LibJS/Runtime/Shape.h>
namespace JS {
ObjectConstructor::ObjectConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Object, *global_object.function_prototype())
{
}
void ObjectConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.prototype, global_object.object_prototype(), 0);
define_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.defineProperty, define_property_, 3, attr);
define_native_function(vm.names.is, is, 2, attr);
define_native_function(vm.names.getOwnPropertyDescriptor, get_own_property_descriptor, 2, attr);
define_native_function(vm.names.getOwnPropertyNames, get_own_property_names, 1, attr);
define_native_function(vm.names.getPrototypeOf, get_prototype_of, 1, attr);
define_native_function(vm.names.setPrototypeOf, set_prototype_of, 2, attr);
define_native_function(vm.names.isExtensible, is_extensible, 1, attr);
define_native_function(vm.names.preventExtensions, prevent_extensions, 1, attr);
define_native_function(vm.names.keys, keys, 1, attr);
define_native_function(vm.names.values, values, 1, attr);
define_native_function(vm.names.entries, entries, 1, attr);
}
ObjectConstructor::~ObjectConstructor()
{
}
Value ObjectConstructor::call()
{
auto value = vm().argument(0);
if (value.is_nullish())
return Object::create_empty(global_object());
return value.to_object(global_object());
}
Value ObjectConstructor::construct(Function&)
{
return call();
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names)
{
if (!vm.argument_count())
return {};
auto* object = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
auto* result = Array::create(global_object);
for (auto& entry : object->indexed_properties())
result->indexed_properties().append(js_string(vm, String::number(entry.index())));
for (auto& it : object->shape().property_table_ordered()) {
if (!it.key.is_string())
continue;
result->indexed_properties().append(js_string(vm, it.key.as_string()));
}
return result;
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_prototype_of)
{
if (!vm.argument_count())
return {};
auto* object = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
return object->prototype();
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::set_prototype_of)
{
if (vm.argument_count() < 2) {
vm.throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfTwoArgs);
return {};
}
auto* object = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
auto prototype_value = vm.argument(1);
Object* prototype;
if (prototype_value.is_null()) {
prototype = nullptr;
} else if (prototype_value.is_object()) {
prototype = &prototype_value.as_object();
} else {
vm.throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType);
return {};
}
if (!object->set_prototype(prototype)) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object, ErrorType::ObjectSetPrototypeOfReturnedFalse);
return {};
}
return object;
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is_extensible)
{
auto argument = vm.argument(0);
if (!argument.is_object())
return Value(false);
return Value(argument.as_object().is_extensible());
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::prevent_extensions)
{
auto argument = vm.argument(0);
if (!argument.is_object())
return argument;
if (!argument.as_object().prevent_extensions()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object, ErrorType::ObjectPreventExtensionsReturnedFalse);
return {};
}
return argument;
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_descriptor)
{
auto* object = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
auto property_key = PropertyName::from_value(global_object, vm.argument(1));
if (vm.exception())
return {};
return object->get_own_property_descriptor_object(property_key);
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::define_property_)
{
if (!vm.argument(0).is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, "Object argument");
return {};
}
if (!vm.argument(2).is_object()) {
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, "Descriptor argument");
return {};
}
auto& object = vm.argument(0).as_object();
auto property_key = StringOrSymbol::from_value(global_object, vm.argument(1));
if (vm.exception())
return {};
auto& descriptor = vm.argument(2).as_object();
if (!object.define_property(property_key, descriptor)) {
if (!vm.exception()) {
if (AK::is<ProxyObject>(object)) {
vm.throw_exception<TypeError>(global_object, ErrorType::ObjectDefinePropertyReturnedFalse);
} else {
vm.throw_exception<TypeError>(global_object, ErrorType::NonExtensibleDefine, property_key.to_display_string());
}
}
return {};
}
return &object;
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::is)
{
return Value(same_value(vm.argument(0), vm.argument(1)));
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::keys)
{
if (!vm.argument_count()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
return obj_arg->get_own_properties(*obj_arg, PropertyKind::Key, true);
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::values)
{
if (!vm.argument_count()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
return obj_arg->get_own_properties(*obj_arg, PropertyKind::Value, true);
}
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
{
if (!vm.argument_count()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ConvertUndefinedToObject);
return {};
}
auto* obj_arg = vm.argument(0).to_object(global_object);
if (vm.exception())
return {};
return obj_arg->get_own_properties(*obj_arg, PropertyKind::KeyAndValue, true);
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class ObjectConstructor final : public NativeFunction {
JS_OBJECT(ObjectConstructor, NativeFunction);
public:
explicit ObjectConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ObjectConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(define_property_);
JS_DECLARE_NATIVE_FUNCTION(is);
JS_DECLARE_NATIVE_FUNCTION(get_own_property_descriptor);
JS_DECLARE_NATIVE_FUNCTION(get_own_property_names);
JS_DECLARE_NATIVE_FUNCTION(get_prototype_of);
JS_DECLARE_NATIVE_FUNCTION(set_prototype_of);
JS_DECLARE_NATIVE_FUNCTION(is_extensible);
JS_DECLARE_NATIVE_FUNCTION(prevent_extensions);
JS_DECLARE_NATIVE_FUNCTION(keys);
JS_DECLARE_NATIVE_FUNCTION(values);
JS_DECLARE_NATIVE_FUNCTION(entries);
};
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <AK/Function.h>
#include <AK/String.h>
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/ObjectPrototype.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/StringObject.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
ObjectPrototype::ObjectPrototype(GlobalObject& global_object)
: Object(Object::ConstructWithoutPrototypeTag::Tag, global_object)
{
}
void ObjectPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
// This must be called after the constructor has returned, so that the below code
// can find the ObjectPrototype through normal paths.
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.hasOwnProperty, has_own_property, 1, attr);
define_native_function(vm.names.toString, to_string, 0, attr);
define_native_function(vm.names.toLocaleString, to_locale_string, 0, attr);
define_native_function(vm.names.valueOf, value_of, 0, attr);
define_native_function(vm.names.propertyIsEnumerable, property_is_enumerable, 1, attr);
define_native_function(vm.names.isPrototypeOf, is_prototype_of, 1, attr);
}
ObjectPrototype::~ObjectPrototype()
{
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
auto name = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
return Value(this_object->has_own_property(name));
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
{
auto this_value = vm.this_value(global_object);
if (this_value.is_undefined())
return js_string(vm, "[object Undefined]");
if (this_value.is_null())
return js_string(vm, "[object Null]");
auto* this_object = this_value.to_object(global_object);
if (!this_object)
return {};
String tag;
auto to_string_tag = this_object->get(global_object.vm().well_known_symbol_to_string_tag());
if (to_string_tag.is_string()) {
tag = to_string_tag.as_string().string();
} else if (this_object->is_array()) {
tag = "Array";
} else if (this_object->is_function()) {
tag = "Function";
} else if (is<Error>(this_object)) {
tag = "Error";
} else if (is<BooleanObject>(this_object)) {
tag = "Boolean";
} else if (is<NumberObject>(this_object)) {
tag = "Number";
} else if (is<StringObject>(this_object)) {
tag = "String";
} else if (is<Date>(this_object)) {
tag = "Date";
} else if (is<RegExpObject>(this_object)) {
tag = "RegExp";
} else {
tag = "Object";
}
return js_string(vm, String::formatted("[object {}]", tag));
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
return this_object->invoke("toString");
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::value_of)
{
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
return this_object->value_of();
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::property_is_enumerable)
{
auto name = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
auto property_descriptor = this_object->get_own_property_descriptor(name);
if (!property_descriptor.has_value())
return Value(false);
return Value(property_descriptor.value().attributes.is_enumerable());
}
JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::is_prototype_of)
{
auto object_argument = vm.argument(0);
if (!object_argument.is_object())
return Value(false);
auto* object = &object_argument.as_object();
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
for (;;) {
object = object->prototype();
if (!object)
return Value(false);
if (same_value(this_object, object))
return Value(true);
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <LibJS/Runtime/Object.h>
namespace JS {
class ObjectPrototype final : public Object {
JS_OBJECT(ObjectPrototype, Object);
public:
explicit ObjectPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ObjectPrototype() override;
// public to serve as intrinsic function %Object.prototype.toString%
JS_DECLARE_NATIVE_FUNCTION(to_string);
private:
JS_DECLARE_NATIVE_FUNCTION(has_own_property);
JS_DECLARE_NATIVE_FUNCTION(to_locale_string);
JS_DECLARE_NATIVE_FUNCTION(value_of);
JS_DECLARE_NATIVE_FUNCTION(property_is_enumerable);
JS_DECLARE_NATIVE_FUNCTION(is_prototype_of);
};
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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.
*/
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
PrimitiveString::PrimitiveString(String string)
: m_string(move(string))
{
}
PrimitiveString::~PrimitiveString()
{
}
PrimitiveString* js_string(Heap& heap, String string)
{
if (string.is_empty())
return &heap.vm().empty_string();
if (string.length() == 1 && (u8)string.characters()[0] < 0x80)
return &heap.vm().single_ascii_character_string(string.characters()[0]);
return heap.allocate_without_global_object<PrimitiveString>(move(string));
}
PrimitiveString* js_string(VM& vm, String string)
{
return js_string(vm.heap(), move(string));
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/String.h>
#include <LibJS/Runtime/Cell.h>
namespace JS {
class PrimitiveString final : public Cell {
public:
explicit PrimitiveString(String);
virtual ~PrimitiveString();
const String& string() const { return m_string; }
private:
virtual const char* class_name() const override { return "PrimitiveString"; }
String m_string;
};
PrimitiveString* js_string(Heap&, String);
PrimitiveString* js_string(VM&, String);
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <AK/Format.h>
#include <AK/Types.h>
namespace JS {
struct Attribute {
enum {
Configurable = 1 << 0,
Enumerable = 1 << 1,
Writable = 1 << 2,
HasGetter = 1 << 3,
HasSetter = 1 << 4,
HasConfigurable = 1 << 5,
HasEnumerable = 1 << 6,
HasWritable = 1 << 7,
};
};
class PropertyAttributes {
public:
PropertyAttributes(u8 bits = 0)
{
m_bits = bits;
if (bits & Attribute::Configurable)
m_bits |= Attribute::HasConfigurable;
if (bits & Attribute::Enumerable)
m_bits |= Attribute::HasEnumerable;
if (bits & Attribute::Writable)
m_bits |= Attribute::HasWritable;
}
bool is_empty() const { return !m_bits; }
bool has_configurable() const { return m_bits & Attribute::HasConfigurable; }
bool has_enumerable() const { return m_bits & Attribute::HasEnumerable; }
bool has_writable() const { return m_bits & Attribute::HasWritable; }
bool has_getter() const { return m_bits & Attribute::HasGetter; }
bool has_setter() const { return m_bits & Attribute::HasSetter; }
bool is_configurable() const { return m_bits & Attribute::Configurable; }
bool is_enumerable() const { return m_bits & Attribute::Enumerable; }
bool is_writable() const { return m_bits & Attribute::Writable; }
void set_has_configurable() { m_bits |= Attribute::HasConfigurable; }
void set_has_enumerable() { m_bits |= Attribute::HasEnumerable; }
void set_has_writable() { m_bits |= Attribute::HasWritable; }
void set_configurable() { m_bits |= Attribute::Configurable; }
void set_enumerable() { m_bits |= Attribute::Enumerable; }
void set_writable() { m_bits |= Attribute::Writable; }
void set_has_getter() { m_bits |= Attribute::HasGetter; }
void set_has_setter() { m_bits |= Attribute::HasSetter; }
bool operator==(const PropertyAttributes& other) const { return m_bits == other.m_bits; }
bool operator!=(const PropertyAttributes& other) const { return m_bits != other.m_bits; }
u8 bits() const { return m_bits; }
private:
u8 m_bits;
};
const PropertyAttributes default_attributes = Attribute::Configurable | Attribute::Writable | Attribute::Enumerable;
}
namespace AK {
template<>
struct Formatter<JS::PropertyAttributes> : Formatter<u8> {
void format(FormatBuilder& builder, const JS::PropertyAttributes& attributes)
{
Formatter<u8>::format(builder, attributes.bits());
}
};
}

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* 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 <AK/FlyString.h>
#include <LibJS/Runtime/StringOrSymbol.h>
namespace JS {
class PropertyName {
public:
enum class Type {
Invalid,
Number,
String,
Symbol,
};
static PropertyName from_value(GlobalObject& global_object, Value value)
{
if (value.is_empty())
return {};
if (value.is_symbol())
return &value.as_symbol();
if (value.is_integer() && value.as_i32() >= 0)
return value.as_i32();
auto string = value.to_string(global_object);
if (string.is_null())
return {};
return string;
}
PropertyName() { }
PropertyName(i32 index)
: m_type(Type::Number)
, m_number(index)
{
ASSERT(index >= 0);
}
PropertyName(const char* chars)
: m_type(Type::String)
, m_string(FlyString(chars))
{
}
PropertyName(const String& string)
: m_type(Type::String)
, m_string(FlyString(string))
{
ASSERT(!string.is_null());
}
PropertyName(const FlyString& string)
: m_type(Type::String)
, m_string(string)
{
ASSERT(!string.is_null());
}
PropertyName(Symbol* symbol)
: m_type(Type::Symbol)
, m_symbol(symbol)
{
ASSERT(symbol);
}
PropertyName(const StringOrSymbol& string_or_symbol)
{
if (string_or_symbol.is_string()) {
m_string = string_or_symbol.as_string();
m_type = Type::String;
} else if (string_or_symbol.is_symbol()) {
m_symbol = const_cast<Symbol*>(string_or_symbol.as_symbol());
m_type = Type::Symbol;
}
}
bool is_valid() const { return m_type != Type::Invalid; }
bool is_number() const { return m_type == Type::Number; }
bool is_string() const { return m_type == Type::String; }
bool is_symbol() const { return m_type == Type::Symbol; }
i32 as_number() const
{
ASSERT(is_number());
return m_number;
}
const FlyString& as_string() const
{
ASSERT(is_string());
return m_string;
}
const Symbol* as_symbol() const
{
ASSERT(is_symbol());
return m_symbol;
}
String to_string() const
{
ASSERT(is_valid());
ASSERT(!is_symbol());
if (is_string())
return as_string();
return String::number(as_number());
}
StringOrSymbol to_string_or_symbol() const
{
ASSERT(is_valid());
ASSERT(!is_number());
if (is_string())
return StringOrSymbol(as_string());
return StringOrSymbol(as_symbol());
}
Value to_value(VM& vm) const
{
if (is_string())
return js_string(vm, m_string);
if (is_number())
return Value(m_number);
if (is_symbol())
return m_symbol;
return js_undefined();
}
private:
Type m_type { Type::Invalid };
FlyString m_string;
Symbol* m_symbol { nullptr };
u32 m_number { 0 };
};
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ProxyConstructor.h>
#include <LibJS/Runtime/ProxyObject.h>
namespace JS {
ProxyConstructor::ProxyConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.Proxy, *global_object.function_prototype())
{
}
void ProxyConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
define_property(vm.names.length, Value(2), Attribute::Configurable);
}
ProxyConstructor::~ProxyConstructor()
{
}
Value ProxyConstructor::call()
{
auto& vm = this->vm();
vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, vm.names.Proxy);
return {};
}
Value ProxyConstructor::construct(Function&)
{
auto& vm = this->vm();
if (vm.argument_count() < 2) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyTwoArguments);
return {};
}
auto target = vm.argument(0);
auto handler = vm.argument(1);
if (!target.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructorBadType, "target", target.to_string_without_side_effects());
return {};
}
if (!handler.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructorBadType, "handler", handler.to_string_without_side_effects());
return {};
}
return ProxyObject::create(global_object(), target.as_object(), handler.as_object());
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/NativeFunction.h>
namespace JS {
class ProxyConstructor final : public NativeFunction {
JS_OBJECT(ProxyConstructor, NativeFunction);
public:
explicit ProxyConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~ProxyConstructor() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
};
}

View file

@ -0,0 +1,559 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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.
*/
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ProxyObject.h>
namespace JS {
bool static is_compatible_property_descriptor(bool is_extensible, PropertyDescriptor new_descriptor, Optional<PropertyDescriptor> current_descriptor_optional)
{
if (!current_descriptor_optional.has_value())
return is_extensible;
auto current_descriptor = current_descriptor_optional.value();
if (new_descriptor.attributes.is_empty() && new_descriptor.value.is_empty() && !new_descriptor.getter && !new_descriptor.setter)
return true;
if (!current_descriptor.attributes.is_configurable()) {
if (new_descriptor.attributes.is_configurable())
return false;
if (new_descriptor.attributes.has_enumerable() && new_descriptor.attributes.is_enumerable() != current_descriptor.attributes.is_enumerable())
return false;
}
if (new_descriptor.is_generic_descriptor())
return true;
if (current_descriptor.is_data_descriptor() != new_descriptor.is_data_descriptor() && !current_descriptor.attributes.is_configurable())
return false;
if (current_descriptor.is_data_descriptor() && new_descriptor.is_data_descriptor() && !current_descriptor.attributes.is_configurable() && !current_descriptor.attributes.is_writable()) {
if (new_descriptor.attributes.is_writable())
return false;
return new_descriptor.value.is_empty() && same_value(new_descriptor.value, current_descriptor.value);
}
return true;
}
ProxyObject* ProxyObject::create(GlobalObject& global_object, Object& target, Object& handler)
{
return global_object.heap().allocate<ProxyObject>(global_object, target, handler, *global_object.object_prototype());
}
ProxyObject::ProxyObject(Object& target, Object& handler, Object& prototype)
: Function(prototype)
, m_target(target)
, m_handler(handler)
{
}
ProxyObject::~ProxyObject()
{
}
Object* ProxyObject::prototype()
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return nullptr;
}
auto trap = m_handler.get(vm.names.getPrototypeOf);
if (vm.exception())
return nullptr;
if (trap.is_empty() || trap.is_nullish())
return m_target.prototype();
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "getPrototypeOf");
return nullptr;
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target));
if (vm.exception())
return nullptr;
if (!trap_result.is_object() && !trap_result.is_null()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetPrototypeOfReturn);
return nullptr;
}
if (m_target.is_extensible()) {
if (vm.exception())
return nullptr;
if (trap_result.is_null())
return nullptr;
return &trap_result.as_object();
}
auto target_proto = m_target.prototype();
if (vm.exception())
return nullptr;
if (!same_value(trap_result, Value(target_proto))) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetPrototypeOfNonExtensible);
return nullptr;
}
return &trap_result.as_object();
}
const Object* ProxyObject::prototype() const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return nullptr;
}
return const_cast<const Object*>(const_cast<ProxyObject*>(this)->prototype());
}
bool ProxyObject::set_prototype(Object* object)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get(vm.names.setPrototypeOf);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.set_prototype(object);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "setPrototypeOf");
return false;
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), Value(object));
if (vm.exception() || !trap_result.to_boolean())
return false;
if (m_target.is_extensible())
return true;
auto* target_proto = m_target.prototype();
if (vm.exception())
return false;
if (!same_value(Value(object), Value(target_proto))) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxySetPrototypeOfNonExtensible);
return false;
}
return true;
}
bool ProxyObject::is_extensible() const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get(vm.names.isExtensible);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.is_extensible();
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "isExtensible");
return {};
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target));
if (vm.exception())
return false;
if (trap_result.to_boolean() != m_target.is_extensible()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyIsExtensibleReturn);
return false;
}
return trap_result.to_boolean();
}
bool ProxyObject::prevent_extensions()
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get(vm.names.preventExtensions);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.prevent_extensions();
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "preventExtensions");
return {};
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target));
if (vm.exception())
return false;
if (trap_result.to_boolean() && m_target.is_extensible()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyPreventExtensionsReturn);
return false;
}
return trap_result.to_boolean();
}
Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(const PropertyName& name) const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get(vm.names.getOwnPropertyDescriptor);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return m_target.get_own_property_descriptor(name);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "getOwnPropertyDescriptor");
return {};
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm));
if (vm.exception())
return {};
if (!trap_result.is_object() && !trap_result.is_undefined()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorReturn);
return {};
}
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm.exception())
return {};
if (trap_result.is_undefined()) {
if (!target_desc.has_value())
return {};
if (!target_desc.value().attributes.is_configurable()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorNonConfigurable);
return {};
}
if (!m_target.is_extensible()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorUndefReturn);
return {};
}
return {};
}
auto result_desc = PropertyDescriptor::from_dictionary(vm, trap_result.as_object());
if (vm.exception())
return {};
if (!is_compatible_property_descriptor(m_target.is_extensible(), result_desc, target_desc)) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorInvalidDescriptor);
return {};
}
if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetOwnDescriptorInvalidNonConfig);
return {};
}
return result_desc;
}
bool ProxyObject::define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get(vm.names.defineProperty);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.define_property(property_name, descriptor, throw_exceptions);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "defineProperty");
return false;
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), property_name.to_value(vm), Value(const_cast<Object*>(&descriptor)));
if (vm.exception() || !trap_result.to_boolean())
return false;
auto target_desc = m_target.get_own_property_descriptor(property_name);
if (vm.exception())
return false;
bool setting_config_false = false;
if (descriptor.has_property(vm.names.configurable) && !descriptor.get(vm.names.configurable).to_boolean())
setting_config_false = true;
if (vm.exception())
return false;
if (!target_desc.has_value()) {
if (!m_target.is_extensible()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropNonExtensible);
return false;
}
if (setting_config_false) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropNonConfigurableNonExisting);
return false;
}
} else {
if (!is_compatible_property_descriptor(m_target.is_extensible(), PropertyDescriptor::from_dictionary(vm, descriptor), target_desc)) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropIncompatibleDescriptor);
return false;
}
if (setting_config_false && target_desc.value().attributes.is_configurable()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDefinePropExistingConfigurable);
return false;
}
}
return true;
}
bool ProxyObject::has_property(const PropertyName& name) const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
auto trap = m_handler.get(vm.names.has);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.has_property(name);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "has");
return false;
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm));
if (vm.exception())
return false;
if (!trap_result.to_boolean()) {
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm.exception())
return false;
if (target_desc.has_value()) {
if (!target_desc.value().attributes.is_configurable()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyHasExistingNonConfigurable);
return false;
}
if (!m_target.is_extensible()) {
if (!vm.exception())
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyHasExistingNonExtensible);
return false;
}
}
}
return trap_result.to_boolean();
}
Value ProxyObject::get(const PropertyName& name, Value receiver) const
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
if (receiver.is_empty())
receiver = Value(const_cast<ProxyObject*>(this));
auto trap = m_handler.get(vm.names.get);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return m_target.get(name, receiver);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "get");
return {};
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), receiver);
if (vm.exception())
return {};
auto target_desc = m_target.get_own_property_descriptor(name);
if (target_desc.has_value()) {
if (vm.exception())
return {};
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(trap_result, target_desc.value().value)) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetImmutableDataProperty);
return {};
}
if (target_desc.value().is_accessor_descriptor() && target_desc.value().getter == nullptr && !trap_result.is_undefined()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyGetNonConfigurableAccessor);
return {};
}
}
return trap_result;
}
bool ProxyObject::put(const PropertyName& name, Value value, Value receiver)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return false;
}
if (receiver.is_empty())
receiver = Value(const_cast<ProxyObject*>(this));
auto trap = m_handler.get(vm.names.set);
if (vm.exception())
return false;
if (trap.is_empty() || trap.is_nullish())
return m_target.put(name, value, receiver);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "set");
return false;
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm), value, receiver);
if (vm.exception() || !trap_result.to_boolean())
return false;
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm.exception())
return false;
if (target_desc.has_value() && !target_desc.value().attributes.is_configurable()) {
if (target_desc.value().is_data_descriptor() && !target_desc.value().attributes.is_writable() && !same_value(value, target_desc.value().value)) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxySetImmutableDataProperty);
return false;
}
if (target_desc.value().is_accessor_descriptor() && !target_desc.value().setter) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxySetNonConfigurableAccessor);
}
}
return true;
}
Value ProxyObject::delete_property(const PropertyName& name)
{
auto& vm = this->vm();
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get(vm.names.deleteProperty);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return m_target.delete_property(name);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "deleteProperty");
return {};
}
auto trap_result = vm.call(trap.as_function(), Value(&m_handler), Value(&m_target), name.to_value(vm));
if (vm.exception())
return {};
if (!trap_result.to_boolean())
return Value(false);
auto target_desc = m_target.get_own_property_descriptor(name);
if (vm.exception())
return {};
if (!target_desc.has_value())
return Value(true);
if (!target_desc.value().attributes.is_configurable()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyDeleteNonConfigurable);
return {};
}
return Value(true);
}
void ProxyObject::visit_edges(Cell::Visitor& visitor)
{
Function::visit_edges(visitor);
visitor.visit(&m_target);
visitor.visit(&m_handler);
}
Value ProxyObject::call()
{
auto& vm = this->vm();
if (!is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, Value(this).to_string_without_side_effects());
return {};
}
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get(vm.names.apply);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return static_cast<Function&>(m_target).call();
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "apply");
return {};
}
MarkedValueList arguments(heap());
arguments.append(Value(&m_target));
arguments.append(Value(&m_handler));
// FIXME: Pass global object
auto arguments_array = Array::create(global_object());
vm.for_each_argument([&](auto& argument) {
arguments_array->indexed_properties().append(argument);
});
arguments.append(arguments_array);
return vm.call(trap.as_function(), Value(&m_handler), move(arguments));
}
Value ProxyObject::construct(Function& new_target)
{
auto& vm = this->vm();
if (!is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, Value(this).to_string_without_side_effects());
return {};
}
if (m_is_revoked) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
return {};
}
auto trap = m_handler.get(vm.names.construct);
if (vm.exception())
return {};
if (trap.is_empty() || trap.is_nullish())
return static_cast<Function&>(m_target).construct(new_target);
if (!trap.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyInvalidTrap, "construct");
return {};
}
MarkedValueList arguments(vm.heap());
arguments.append(Value(&m_target));
auto arguments_array = Array::create(global_object());
vm.for_each_argument([&](auto& argument) {
arguments_array->indexed_properties().append(argument);
});
arguments.append(arguments_array);
arguments.append(Value(&new_target));
auto result = vm.call(trap.as_function(), Value(&m_handler), move(arguments));
if (!result.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyConstructBadReturnType);
return {};
}
return result;
}
const FlyString& ProxyObject::name() const
{
ASSERT(is_function());
return static_cast<Function&>(m_target).name();
}
LexicalEnvironment* ProxyObject::create_environment()
{
ASSERT(is_function());
return static_cast<Function&>(m_target).create_environment();
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
* 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 <LibJS/Runtime/Function.h>
namespace JS {
class ProxyObject final : public Function {
JS_OBJECT(ProxyObject, Function);
public:
static ProxyObject* create(GlobalObject&, Object& target, Object& handler);
ProxyObject(Object& target, Object& handler, Object& prototype);
virtual ~ProxyObject() override;
virtual Value call() override;
virtual Value construct(Function& new_target) override;
virtual const FlyString& name() const override;
virtual LexicalEnvironment* create_environment() override;
const Object& target() const { return m_target; }
const Object& handler() const { return m_handler; }
virtual Object* prototype() override;
virtual const Object* prototype() const override;
virtual bool set_prototype(Object* object) override;
virtual bool is_extensible() const override;
virtual bool prevent_extensions() override;
virtual Optional<PropertyDescriptor> get_own_property_descriptor(const PropertyName&) const override;
virtual bool define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions = true) override;
virtual bool has_property(const PropertyName& name) const override;
virtual Value get(const PropertyName& name, Value receiver) const override;
virtual bool put(const PropertyName& name, Value value, Value receiver) override;
virtual Value delete_property(const PropertyName& name) override;
void revoke() { m_is_revoked = true; }
private:
virtual void visit_edges(Visitor&) override;
virtual bool is_function() const override { return m_target.is_function(); }
virtual bool is_array() const override { return m_target.is_array(); };
Object& m_target;
Object& m_handler;
bool m_is_revoked { false };
};
}

Some files were not shown because too many files have changed in this diff Show more