mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibJS: Add Function() and Function.prototype
This commit is contained in:
parent
4d931b524d
commit
2944039d6b
Notes:
sideshowbarker
2024-07-19 07:56:21 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/2944039d6b2 Pull-request: https://github.com/SerenityOS/serenity/pull/1622 Reviewed-by: https://github.com/awesomekling ✅
15 changed files with 463 additions and 4 deletions
|
@ -333,6 +333,8 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
|
|||
case Value::Type::String:
|
||||
return js_string(interpreter, "string");
|
||||
case Value::Type::Object:
|
||||
if (lhs_result.as_object().is_function())
|
||||
return js_string(interpreter, "function");
|
||||
return js_string(interpreter, "object");
|
||||
case Value::Type::Boolean:
|
||||
return js_string(interpreter, "boolean");
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <LibJS/Runtime/DatePrototype.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/ErrorPrototype.h>
|
||||
#include <LibJS/Runtime/FunctionPrototype.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
|
@ -47,6 +48,7 @@ Interpreter::Interpreter()
|
|||
m_empty_object_shape = heap().allocate<Shape>();
|
||||
|
||||
m_object_prototype = heap().allocate<ObjectPrototype>();
|
||||
m_function_prototype = heap().allocate<FunctionPrototype>();
|
||||
m_string_prototype = heap().allocate<StringPrototype>();
|
||||
m_array_prototype = heap().allocate<ArrayPrototype>();
|
||||
m_error_prototype = heap().allocate<ErrorPrototype>();
|
||||
|
@ -171,6 +173,7 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
|
|||
roots.set(m_array_prototype);
|
||||
roots.set(m_error_prototype);
|
||||
roots.set(m_date_prototype);
|
||||
roots.set(m_function_prototype);
|
||||
|
||||
roots.set(m_exception);
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
Object* array_prototype() { return m_array_prototype; }
|
||||
Object* error_prototype() { return m_error_prototype; }
|
||||
Object* date_prototype() { return m_date_prototype; }
|
||||
Object* function_prototype() { return m_function_prototype; }
|
||||
|
||||
Exception* exception() { return m_exception; }
|
||||
void clear_exception() { m_exception = nullptr; }
|
||||
|
@ -168,6 +169,7 @@ private:
|
|||
Object* m_array_prototype { nullptr };
|
||||
Object* m_error_prototype { nullptr };
|
||||
Object* m_date_prototype { nullptr };
|
||||
Object* m_function_prototype { nullptr };
|
||||
|
||||
Exception* m_exception { nullptr };
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ OBJS = \
|
|||
Runtime/ErrorPrototype.o \
|
||||
Runtime/Exception.o \
|
||||
Runtime/Function.o \
|
||||
Runtime/FunctionConstructor.o \
|
||||
Runtime/FunctionPrototype.o \
|
||||
Runtime/GlobalObject.o \
|
||||
Runtime/MathObject.o \
|
||||
Runtime/NativeFunction.o \
|
||||
|
|
|
@ -24,16 +24,14 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Function::Function()
|
||||
{
|
||||
put("prototype", heap().allocate<Object>());
|
||||
set_prototype(interpreter().function_prototype());
|
||||
}
|
||||
|
||||
Function::~Function()
|
||||
|
|
77
Libraries/LibJS/Runtime/FunctionConstructor.cpp
Normal file
77
Libraries/LibJS/Runtime/FunctionConstructor.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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/ScriptFunction.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
FunctionConstructor::FunctionConstructor()
|
||||
{
|
||||
put("prototype", interpreter().function_prototype());
|
||||
put("length", Value(1));
|
||||
}
|
||||
|
||||
FunctionConstructor::~FunctionConstructor()
|
||||
{
|
||||
}
|
||||
|
||||
Value FunctionConstructor::call(Interpreter& interpreter)
|
||||
{
|
||||
return construct(interpreter);
|
||||
}
|
||||
|
||||
Value FunctionConstructor::construct(Interpreter& interpreter)
|
||||
{
|
||||
String parameters_source = "";
|
||||
String body_source = "";
|
||||
if (interpreter.argument_count() == 1)
|
||||
body_source = interpreter.argument(0).to_string();
|
||||
if (interpreter.argument_count() > 1) {
|
||||
Vector<String> parameters;
|
||||
for (size_t i = 0; i < interpreter.argument_count() - 1; ++i)
|
||||
parameters.append(interpreter.argument(i).to_string());
|
||||
StringBuilder parameters_builder;
|
||||
parameters_builder.join(',', parameters);
|
||||
parameters_source = parameters_builder.build();
|
||||
body_source = interpreter.argument(interpreter.argument_count() - 1).to_string();
|
||||
}
|
||||
auto source = String::format("function (%s) { %s }", parameters_source.characters(), body_source.characters());
|
||||
auto parser = Parser(Lexer(source));
|
||||
auto function_expression = parser.parse_function_node<FunctionExpression>();
|
||||
if (parser.has_errors()) {
|
||||
// FIXME: The parser should expose parsing error strings rather than just fprintf()'ing them
|
||||
return interpreter.heap().allocate<Error>("SyntaxError", "");
|
||||
}
|
||||
return function_expression->execute(interpreter);
|
||||
}
|
||||
|
||||
}
|
46
Libraries/LibJS/Runtime/FunctionConstructor.h
Normal file
46
Libraries/LibJS/Runtime/FunctionConstructor.h
Normal 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/NativeFunction.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class FunctionConstructor final : public NativeFunction {
|
||||
public:
|
||||
FunctionConstructor();
|
||||
virtual ~FunctionConstructor() override;
|
||||
|
||||
virtual Value call(Interpreter&) override;
|
||||
virtual Value construct(Interpreter&) override;
|
||||
|
||||
private:
|
||||
virtual bool has_constructor() const override { return true; }
|
||||
virtual const char* class_name() const override { return "FunctionConstructor"; }
|
||||
};
|
||||
|
||||
}
|
123
Libraries/LibJS/Runtime/FunctionPrototype.cpp
Normal file
123
Libraries/LibJS/Runtime/FunctionPrototype.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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/Error.h>
|
||||
#include <LibJS/Runtime/Function.h>
|
||||
#include <LibJS/Runtime/FunctionPrototype.h>
|
||||
#include <LibJS/Runtime/ScriptFunction.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
FunctionPrototype::FunctionPrototype()
|
||||
{
|
||||
put_native_function("apply", apply, 2);
|
||||
put_native_function("bind", bind, 1);
|
||||
put_native_function("call", call, 1);
|
||||
put_native_function("toString", to_string);
|
||||
put("length", Value(0));
|
||||
}
|
||||
|
||||
FunctionPrototype::~FunctionPrototype()
|
||||
{
|
||||
}
|
||||
|
||||
Value FunctionPrototype::apply(Interpreter& interpreter)
|
||||
{
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (!this_object->is_function())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
||||
auto function = static_cast<Function*>(this_object);
|
||||
auto this_arg = interpreter.argument(0);
|
||||
auto arg_array = interpreter.argument(1);
|
||||
if (arg_array.is_null() || arg_array.is_undefined())
|
||||
return interpreter.call(function, this_arg);
|
||||
if (!arg_array.is_object())
|
||||
return interpreter.throw_exception<Error>("TypeError", "argument array must be an object");
|
||||
size_t length = 0;
|
||||
auto length_property = arg_array.as_object().get("length");
|
||||
if (length_property.has_value())
|
||||
length = length_property.value().to_number().to_i32();
|
||||
Vector<Value> arguments;
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
arguments.append(arg_array.as_object().get(String::number(i)).value_or(js_undefined()));
|
||||
return interpreter.call(function, this_arg, arguments);
|
||||
}
|
||||
|
||||
Value FunctionPrototype::bind(Interpreter& interpreter)
|
||||
{
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
// FIXME: Implement me :^)
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
Value FunctionPrototype::call(Interpreter& interpreter)
|
||||
{
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (!this_object->is_function())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
||||
auto function = static_cast<Function*>(this_object);
|
||||
auto this_arg = interpreter.argument(0);
|
||||
Vector<Value> arguments;
|
||||
if (interpreter.argument_count() > 1) {
|
||||
for (size_t i = 1; i < interpreter.argument_count(); ++i)
|
||||
arguments.append(interpreter.argument(i));
|
||||
}
|
||||
return interpreter.call(function, this_arg, arguments);
|
||||
}
|
||||
|
||||
Value FunctionPrototype::to_string(Interpreter& interpreter)
|
||||
{
|
||||
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||
if (!this_object)
|
||||
return {};
|
||||
if (!this_object->is_function())
|
||||
return interpreter.throw_exception<Error>("TypeError", "Not a Function object");
|
||||
// FIXME: Functions should be able to know their name, if any
|
||||
if (this_object->is_native_function()) {
|
||||
auto function_source = String::format("function () {\n [%s]\n}", this_object->class_name());
|
||||
return js_string(interpreter, function_source);
|
||||
}
|
||||
auto parameters = static_cast<ScriptFunction*>(this_object)->parameters();
|
||||
StringBuilder parameters_builder;
|
||||
parameters_builder.join(", ", parameters);
|
||||
// FIXME: ASTNodes should be able to dump themselves to source strings - something like this:
|
||||
// auto& body = static_cast<ScriptFunction*>(this_object)->body();
|
||||
// auto body_source = body.to_source();
|
||||
auto function_source = String::format("function (%s) {\n %s\n}", parameters_builder.build().characters(), "???");
|
||||
return js_string(interpreter, function_source);
|
||||
}
|
||||
|
||||
}
|
47
Libraries/LibJS/Runtime/FunctionPrototype.h
Normal file
47
Libraries/LibJS/Runtime/FunctionPrototype.h
Normal 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 FunctionPrototype final : public Object {
|
||||
public:
|
||||
FunctionPrototype();
|
||||
virtual ~FunctionPrototype() override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "FunctionPrototype"; }
|
||||
|
||||
static Value apply(Interpreter&);
|
||||
static Value bind(Interpreter&);
|
||||
static Value call(Interpreter&);
|
||||
static Value to_string(Interpreter&);
|
||||
};
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include <LibJS/Runtime/ConsoleObject.h>
|
||||
#include <LibJS/Runtime/DateConstructor.h>
|
||||
#include <LibJS/Runtime/ErrorConstructor.h>
|
||||
#include <LibJS/Runtime/FunctionConstructor.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/MathObject.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
|
@ -26,6 +27,7 @@ GlobalObject::GlobalObject()
|
|||
put("console", heap().allocate<ConsoleObject>());
|
||||
put("Date", heap().allocate<DateConstructor>());
|
||||
put("Error", heap().allocate<ErrorConstructor>());
|
||||
put("Function", heap().allocate<FunctionConstructor>());
|
||||
put("Math", heap().allocate<MathObject>());
|
||||
put("Object", heap().allocate<ObjectConstructor>());
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ ScriptFunction::ScriptFunction(const ScopeNode& body, Vector<FlyString> paramete
|
|||
: m_body(body)
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
put("prototype", heap().allocate<Object>());
|
||||
put_native_property("length", length_getter, length_setter);
|
||||
}
|
||||
|
||||
|
|
29
Libraries/LibJS/Tests/Function.js
Normal file
29
Libraries/LibJS/Tests/Function.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
function assert(x) { if (!x) throw 1; }
|
||||
|
||||
try {
|
||||
assert(Function.length === 1);
|
||||
assert(Function.prototype.length === 0);
|
||||
assert(typeof Function() === "function");
|
||||
assert(typeof new Function() === "function");
|
||||
assert(Function()() === undefined);
|
||||
assert(new Function()() === undefined);
|
||||
assert(Function("return 42")() === 42);
|
||||
assert(new Function("return 42")() === 42);
|
||||
assert(new Function("foo", "return foo")(42) === 42);
|
||||
assert(new Function("foo,bar", "return foo + bar")(1, 2) === 3);
|
||||
assert(new Function("foo", "bar", "return foo + bar")(1, 2) === 3);
|
||||
assert(new Function("foo", "bar,baz", "return foo + bar + baz")(1, 2, 3) === 6);
|
||||
assert(new Function("foo", "bar", "baz", "return foo + bar + baz")(1, 2, 3) === 6);
|
||||
assert(new Function("foo", "if (foo) { return 42; } else { return 'bar'; }")(true) === 42);
|
||||
assert(new Function("foo", "if (foo) { return 42; } else { return 'bar'; }")(false) === "bar");
|
||||
assert(new Function("return typeof Function()")() === "function");
|
||||
// FIXME: This is equivalent to
|
||||
// (function (x) { return function (y) { return x + y;} })(1)(2)
|
||||
// and should totally work, but both currently fail with
|
||||
// Uncaught exception: [ReferenceError]: 'x' not known
|
||||
// assert(new Function("x", "return function (y) { return x + y };")(1)(2) === 3);
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e.message);
|
||||
}
|
53
Libraries/LibJS/Tests/Function.prototype.apply.js
Normal file
53
Libraries/LibJS/Tests/Function.prototype.apply.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
function assert(x) { if (!x) throw 1; }
|
||||
|
||||
try {
|
||||
function Foo(arg) {
|
||||
this.foo = arg;
|
||||
}
|
||||
function Bar(arg) {
|
||||
this.bar = arg;
|
||||
}
|
||||
function FooBar(arg) {
|
||||
Foo.apply(this, [arg]);
|
||||
Bar.apply(this, [arg]);
|
||||
}
|
||||
function FooBarBaz(arg) {
|
||||
Foo.apply(this, [arg]);
|
||||
Bar.apply(this, [arg]);
|
||||
this.baz = arg;
|
||||
}
|
||||
|
||||
assert(Function.prototype.apply.length === 2);
|
||||
|
||||
var foo = new Foo("test");
|
||||
assert(foo.foo === "test");
|
||||
assert(foo.bar === undefined);
|
||||
assert(foo.baz === undefined);
|
||||
|
||||
var bar = new Bar("test");
|
||||
assert(bar.foo === undefined);
|
||||
assert(bar.bar === "test");
|
||||
assert(bar.baz === undefined);
|
||||
|
||||
var foobar = new FooBar("test");
|
||||
assert(foobar.foo === "test");
|
||||
assert(foobar.bar === "test");
|
||||
assert(foobar.baz === undefined);
|
||||
|
||||
var foobarbaz = new FooBarBaz("test");
|
||||
assert(foobarbaz.foo === "test");
|
||||
assert(foobarbaz.bar === "test");
|
||||
assert(foobarbaz.baz === "test");
|
||||
|
||||
assert(Math.abs.apply(null, [-1]) === 1);
|
||||
|
||||
var add = (x, y) => x + y;
|
||||
assert(add.apply(null, [1, 2]) === 3);
|
||||
|
||||
var multiply = function (x, y) { return x * y; };
|
||||
assert(multiply.apply(null, [3, 4]) === 12);
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
53
Libraries/LibJS/Tests/Function.prototype.call.js
Normal file
53
Libraries/LibJS/Tests/Function.prototype.call.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
function assert(x) { if (!x) throw 1; }
|
||||
|
||||
try {
|
||||
function Foo(arg) {
|
||||
this.foo = arg;
|
||||
}
|
||||
function Bar(arg) {
|
||||
this.bar = arg;
|
||||
}
|
||||
function FooBar(arg) {
|
||||
Foo.call(this, arg);
|
||||
Bar.call(this, arg);
|
||||
}
|
||||
function FooBarBaz(arg) {
|
||||
Foo.call(this, arg);
|
||||
Bar.call(this, arg);
|
||||
this.baz = arg;
|
||||
}
|
||||
|
||||
assert(Function.prototype.call.length === 1);
|
||||
|
||||
var foo = new Foo("test");
|
||||
assert(foo.foo === "test");
|
||||
assert(foo.bar === undefined);
|
||||
assert(foo.baz === undefined);
|
||||
|
||||
var bar = new Bar("test");
|
||||
assert(bar.foo === undefined);
|
||||
assert(bar.bar === "test");
|
||||
assert(bar.baz === undefined);
|
||||
|
||||
var foobar = new FooBar("test");
|
||||
assert(foobar.foo === "test");
|
||||
assert(foobar.bar === "test");
|
||||
assert(foobar.baz === undefined);
|
||||
|
||||
var foobarbaz = new FooBarBaz("test");
|
||||
assert(foobarbaz.foo === "test");
|
||||
assert(foobarbaz.bar === "test");
|
||||
assert(foobarbaz.baz === "test");
|
||||
|
||||
assert(Math.abs.call(null, -1) === 1);
|
||||
|
||||
var add = (x, y) => x + y;
|
||||
assert(add.call(null, 1, 2) === 3);
|
||||
|
||||
var multiply = function (x, y) { return x * y; };
|
||||
assert(multiply.call(null, 3, 4) === 12);
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
21
Libraries/LibJS/Tests/Function.prototype.toString.js
Normal file
21
Libraries/LibJS/Tests/Function.prototype.toString.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
function assert(x) { if (!x) throw 1; }
|
||||
|
||||
try {
|
||||
assert((function() {}).toString() === "function () {\n ???\n}");
|
||||
assert((function(foo) {}).toString() === "function (foo) {\n ???\n}");
|
||||
assert((function(foo, bar, baz) {}).toString() === "function (foo, bar, baz) {\n ???\n}");
|
||||
assert((function(foo, bar, baz) {
|
||||
if (foo) {
|
||||
return baz;
|
||||
} else if (bar) {
|
||||
return foo;
|
||||
}
|
||||
return bar + 42;
|
||||
}).toString() === "function (foo, bar, baz) {\n ???\n}");
|
||||
assert(console.log.toString() === "function () {\n [NativeFunction]\n}");
|
||||
assert(Function.toString() === "function () {\n [FunctionConstructor]\n}");
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
Loading…
Add table
Reference in a new issue