summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibJS/Runtime/FunctionPrototype.cpp1
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.cpp1
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.h6
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp1
-rw-r--r--Libraries/LibJS/Runtime/ScriptFunction.cpp29
-rw-r--r--Libraries/LibJS/Runtime/ScriptFunction.h2
-rw-r--r--Libraries/LibJS/Tests/Array.js9
-rw-r--r--Libraries/LibJS/Tests/Boolean.js3
-rw-r--r--Libraries/LibJS/Tests/Date.js11
-rw-r--r--Libraries/LibJS/Tests/Error.js4
-rw-r--r--Libraries/LibJS/Tests/Function.js3
-rw-r--r--Libraries/LibJS/Tests/Number.js4
-rw-r--r--Libraries/LibJS/Tests/Object.js14
-rw-r--r--Libraries/LibJS/Tests/String.js23
-rw-r--r--Libraries/LibJS/Tests/function-name.js21
-rw-r--r--Libraries/LibWeb/Bindings/WindowObject.cpp2
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()