diff options
-rw-r--r-- | Libraries/LibJS/Runtime/FunctionPrototype.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/GlobalObject.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/GlobalObject.h | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.cpp | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ScriptFunction.cpp | 29 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ScriptFunction.h | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Array.js | 9 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Boolean.js | 3 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Date.js | 11 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Error.js | 4 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Function.js | 3 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Number.js | 4 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Object.js | 14 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/String.js | 23 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/function-name.js | 21 | ||||
-rw-r--r-- | Libraries/LibWeb/Bindings/WindowObject.cpp | 2 |
16 files changed, 118 insertions, 16 deletions
diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index f0aa7041b1..7be81921c5 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -51,6 +51,7 @@ void FunctionPrototype::initialize() put_native_function("call", call, 1, attr); put_native_function("toString", to_string, 0, attr); put("length", Value(0), Attribute::Configurable); + put("name", js_string(heap(), ""), Attribute::Configurable); } FunctionPrototype::~FunctionPrototype() diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index bd79f7ebf7..baaf16f62e 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -61,6 +61,7 @@ template<typename ConstructorType> void GlobalObject::add_constructor(const FlyString& property_name, ConstructorType*& constructor, Object& prototype) { constructor = heap().allocate<ConstructorType>(); + constructor->put("name", js_string(heap(), property_name), Attribute::Configurable); prototype.put("constructor", constructor); put(property_name, constructor, Attribute::Writable | Attribute::Configurable); } diff --git a/Libraries/LibJS/Runtime/GlobalObject.h b/Libraries/LibJS/Runtime/GlobalObject.h index d28383fac9..811cc28007 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.h +++ b/Libraries/LibJS/Runtime/GlobalObject.h @@ -48,6 +48,9 @@ public: protected: virtual void visit_children(Visitor&) override; + template<typename ConstructorType> + void add_constructor(const FlyString& property_name, ConstructorType*&, Object& prototype); + private: virtual const char* class_name() const override { return "GlobalObject"; } @@ -55,9 +58,6 @@ private: static Value is_nan(Interpreter&); static Value is_finite(Interpreter&); - template<typename ConstructorType> - void add_constructor(const FlyString& property_name, ConstructorType*&, Object& prototype); - Shape* m_empty_object_shape { nullptr }; #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \ diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index a30dabf90c..3e2e677ff6 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -397,6 +397,7 @@ bool Object::put_native_function(const FlyString& property_name, AK::Function<Va { auto* function = NativeFunction::create(interpreter(), interpreter().global_object(), property_name, move(native_function)); function->put("length", Value(length), Attribute::Configurable); + function->put("name", js_string(heap(), property_name), Attribute::Configurable); return put(property_name, function, attributes); } diff --git a/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Libraries/LibJS/Runtime/ScriptFunction.cpp index 38a1096c17..042ad99872 100644 --- a/Libraries/LibJS/Runtime/ScriptFunction.cpp +++ b/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -34,6 +34,18 @@ namespace JS { +static ScriptFunction* script_function_from(Interpreter& interpreter) +{ + auto* this_object = interpreter.this_value().to_object(interpreter.heap()); + if (!this_object) + return nullptr; + if (!this_object->is_function()) { + interpreter.throw_exception<TypeError>("Not a function"); + return nullptr; + } + return static_cast<ScriptFunction*>(this_object); +} + ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment) { return global_object.heap().allocate<ScriptFunction>(name, body, move(parameters), parent_environment, *global_object.function_prototype()); @@ -47,7 +59,8 @@ ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vec , m_parent_environment(parent_environment) { put("prototype", Object::create_empty(interpreter(), interpreter().global_object()), 0); - put_native_property("length", length_getter, length_setter, Attribute::Configurable); + put_native_property("length", length_getter, nullptr, Attribute::Configurable); + put_native_property("name", name_getter, nullptr, Attribute::Configurable); } ScriptFunction::~ScriptFunction() @@ -101,16 +114,18 @@ Value ScriptFunction::construct(Interpreter& interpreter) Value ScriptFunction::length_getter(Interpreter& interpreter) { - auto* this_object = interpreter.this_value().to_object(interpreter.heap()); - if (!this_object) + auto* function = script_function_from(interpreter); + if (!function) return {}; - if (!this_object->is_function()) - return interpreter.throw_exception<TypeError>("Not a function"); - return Value(static_cast<i32>(static_cast<const ScriptFunction*>(this_object)->parameters().size())); + return Value(static_cast<i32>(function->parameters().size())); } -void ScriptFunction::length_setter(Interpreter&, Value) +Value ScriptFunction::name_getter(Interpreter& interpreter) { + auto* function = script_function_from(interpreter); + if (!function) + return {}; + return js_string(interpreter, function->name().is_null() ? "" : function->name()); } } diff --git a/Libraries/LibJS/Runtime/ScriptFunction.h b/Libraries/LibJS/Runtime/ScriptFunction.h index eb6da007c8..23ccb3c323 100644 --- a/Libraries/LibJS/Runtime/ScriptFunction.h +++ b/Libraries/LibJS/Runtime/ScriptFunction.h @@ -52,7 +52,7 @@ private: virtual void visit_children(Visitor&) override; static Value length_getter(Interpreter&); - static void length_setter(Interpreter&, Value); + static Value name_getter(Interpreter&); FlyString m_name; NonnullRefPtr<Statement> m_body; diff --git a/Libraries/LibJS/Tests/Array.js b/Libraries/LibJS/Tests/Array.js index 122f1501a7..a6ecb398c8 100644 --- a/Libraries/LibJS/Tests/Array.js +++ b/Libraries/LibJS/Tests/Array.js @@ -2,15 +2,16 @@ load("test-common.js"); try { assert(Array.length === 1); + assert(Array.name === "Array"); assert(Array.prototype.length === 0); + assert(typeof Array() === "object"); assert(typeof new Array() === "object"); - x = new Array(5); - - assert(x.length === 5); + var a = new Array(5); + assert(a.length === 5); console.log("PASS"); } catch (e) { - console.log("FAIL: " + e.message); + console.log("FAIL: " + e); } diff --git a/Libraries/LibJS/Tests/Boolean.js b/Libraries/LibJS/Tests/Boolean.js index c77bc04f39..9f9758ced2 100644 --- a/Libraries/LibJS/Tests/Boolean.js +++ b/Libraries/LibJS/Tests/Boolean.js @@ -2,6 +2,9 @@ load("test-common.js"); try { assert(Boolean.length === 1); + assert(Boolean.name === "Boolean"); + assert(Boolean.prototype.length === undefined); + assert(typeof new Boolean() === "object"); assert(new Boolean().valueOf() === false); diff --git a/Libraries/LibJS/Tests/Date.js b/Libraries/LibJS/Tests/Date.js new file mode 100644 index 0000000000..383864d604 --- /dev/null +++ b/Libraries/LibJS/Tests/Date.js @@ -0,0 +1,11 @@ +load("test-common.js"); + +try { + assert(Date.length === 7); + assert(Date.name === "Date"); + assert(Date.prototype.length === undefined); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/Error.js b/Libraries/LibJS/Tests/Error.js index 0338dded12..ed920cb9ba 100644 --- a/Libraries/LibJS/Tests/Error.js +++ b/Libraries/LibJS/Tests/Error.js @@ -1,6 +1,10 @@ load("test-common.js"); try { + assert(Error.length === 1); + assert(Error.name === "Error"); + assert(Error.prototype.length === undefined); + var e; e = Error(); diff --git a/Libraries/LibJS/Tests/Function.js b/Libraries/LibJS/Tests/Function.js index 8ddcb691d6..946ff73270 100644 --- a/Libraries/LibJS/Tests/Function.js +++ b/Libraries/LibJS/Tests/Function.js @@ -2,7 +2,9 @@ load("test-common.js"); try { assert(Function.length === 1); + assert(Function.name === "Function"); assert(Function.prototype.length === 0); + assert(Function.prototype.name === ""); assert(typeof Function() === "function"); assert(typeof new Function() === "function"); @@ -21,6 +23,7 @@ try { assert(new Function("return typeof Function()")() === "function"); assert(new Function("x", "return function (y) { return x + y };")(1)(2) === 3); + assert(new Function().name === "anonymous"); assert(new Function().toString() === "function anonymous() {\n ???\n}"); console.log("PASS"); diff --git a/Libraries/LibJS/Tests/Number.js b/Libraries/LibJS/Tests/Number.js index ba16723525..850d41eb9a 100644 --- a/Libraries/LibJS/Tests/Number.js +++ b/Libraries/LibJS/Tests/Number.js @@ -2,8 +2,12 @@ load("test-common.js"); try { assert(Number.length === 1); + assert(Number.name === "Number"); + assert(Number.prototype.length === undefined); + assert(typeof Number() === "number"); assert(typeof new Number() === "object"); + assert(Number() === 0); assert(new Number().valueOf() === 0); assert(Number("42") === 42); diff --git a/Libraries/LibJS/Tests/Object.js b/Libraries/LibJS/Tests/Object.js new file mode 100644 index 0000000000..b51e0a4abf --- /dev/null +++ b/Libraries/LibJS/Tests/Object.js @@ -0,0 +1,14 @@ +load("test-common.js"); + +try { + assert(Object.length === 1); + assert(Object.name === "Object"); + assert(Object.prototype.length === undefined); + + assert(typeof Object() === "object"); + assert(typeof new Object() === "object"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/String.js b/Libraries/LibJS/Tests/String.js new file mode 100644 index 0000000000..38ccccfb29 --- /dev/null +++ b/Libraries/LibJS/Tests/String.js @@ -0,0 +1,23 @@ +load("test-common.js"); + +try { + assert(String.length === 1); + assert(String.name === "String"); + assert(String.prototype.length === 0); + + assert(typeof String() === "string"); + assert(typeof new String() === "object"); + + assert(String() === ""); + assert(new String().valueOf() === ""); + assert(String("foo") === "foo"); + assert(new String("foo").valueOf() === "foo"); + assert(String(123) === "123"); + assert(new String(123).valueOf() === "123"); + assert(String(123) === "123"); + assert(new String(123).valueOf() === "123"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/function-name.js b/Libraries/LibJS/Tests/function-name.js new file mode 100644 index 0000000000..163dbab8b1 --- /dev/null +++ b/Libraries/LibJS/Tests/function-name.js @@ -0,0 +1,21 @@ +load("test-common.js"); + +try { + var f = function () { } + assert(f.name === ""); + assert((f.name = "f") === "f"); + assert(f.name === ""); + + function foo() { } + assert(foo.name === "foo"); + assert((foo.name = "bar") === "bar"); + assert(foo.name === "foo"); + + assert(console.log.name === "log"); + assert((console.log.name = "warn") === "warn"); + assert(console.log.name === "log"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibWeb/Bindings/WindowObject.cpp b/Libraries/LibWeb/Bindings/WindowObject.cpp index 0e00bb6861..bab0a17316 100644 --- a/Libraries/LibWeb/Bindings/WindowObject.cpp +++ b/Libraries/LibWeb/Bindings/WindowObject.cpp @@ -64,7 +64,7 @@ void WindowObject::initialize() m_xhr_prototype = heap().allocate<XMLHttpRequestPrototype>(); m_xhr_constructor = heap().allocate<XMLHttpRequestConstructor>(); m_xhr_constructor->put("prototype", m_xhr_prototype, 0); - put("XMLHttpRequest", m_xhr_constructor, JS::Attribute::Writable | JS::Attribute::Configurable); + add_constructor("XMLHttpRequest", m_xhr_constructor, *m_xhr_prototype); } WindowObject::~WindowObject() |