diff options
author | Linus Groh <mail@linusgroh.de> | 2020-06-06 01:14:10 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-07 19:29:40 +0200 |
commit | 0ff9d7e1898c224033fde7b03ac9c92db893bfca (patch) | |
tree | bafbbc17fa7c6fdcc2b07c4c4e806f8bfc2eebaa /Libraries | |
parent | 40829b849ae30d3a9de330d4d66af74f547fbaf1 (diff) | |
download | serenity-0ff9d7e1898c224033fde7b03ac9c92db893bfca.zip |
LibJS: Add BigInt
Diffstat (limited to 'Libraries')
31 files changed, 1908 insertions, 635 deletions
diff --git a/Libraries/LibGUI/JSSyntaxHighlighter.cpp b/Libraries/LibGUI/JSSyntaxHighlighter.cpp index 657afd4599..1de5d0bd72 100644 --- a/Libraries/LibGUI/JSSyntaxHighlighter.cpp +++ b/Libraries/LibGUI/JSSyntaxHighlighter.cpp @@ -40,6 +40,7 @@ static TextStyle style_for_token_type(Gfx::Palette palette, JS::TokenType type) case JS::TokenType::Eof: return { palette.syntax_comment() }; case JS::TokenType::NumericLiteral: + case JS::TokenType::BigIntLiteral: return { palette.syntax_number() }; case JS::TokenType::StringLiteral: case JS::TokenType::TemplateLiteralStart: diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 2f12a49e36..38d2523370 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -29,10 +29,12 @@ #include <AK/HashMap.h> #include <AK/ScopeGuard.h> #include <AK/StringBuilder.h> +#include <LibCrypto/BigInt/SignedBigInteger.h> #include <LibJS/AST.h> #include <LibJS/Interpreter.h> #include <LibJS/Runtime/Accessor.h> #include <LibJS/Runtime/Array.h> +#include <LibJS/Runtime/BigInt.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/MarkedValueList.h> @@ -635,6 +637,8 @@ Value UnaryExpression::execute(Interpreter& interpreter) const return js_string(interpreter, "boolean"); case Value::Type::Symbol: return js_string(interpreter, "symbol"); + case Value::Type::BigInt: + return js_string(interpreter, "bigint"); default: ASSERT_NOT_REACHED(); } @@ -834,6 +838,12 @@ void NumericLiteral::dump(int indent) const printf("NumericLiteral %g\n", m_value); } +void BigIntLiteral::dump(int indent) const +{ + print_indent(indent); + printf("BigIntLiteral %s\n", m_value.characters()); +} + void BooleanLiteral::dump(int indent) const { print_indent(indent); @@ -1108,23 +1118,28 @@ Value UpdateExpression::execute(Interpreter& interpreter) const auto old_value = reference.get(interpreter); if (interpreter.exception()) return {}; - old_value = old_value.to_number(interpreter); + old_value = old_value.to_numeric(interpreter); if (interpreter.exception()) return {}; - int op_result = 0; + Value new_value; switch (m_op) { case UpdateOp::Increment: - op_result = 1; + if (old_value.is_number()) + new_value = Value(old_value.as_double() + 1); + else + new_value = js_bigint(interpreter, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 })); break; case UpdateOp::Decrement: - op_result = -1; + if (old_value.is_number()) + new_value = Value(old_value.as_double() - 1); + else + new_value = js_bigint(interpreter, old_value.as_bigint().big_integer().minus(Crypto::SignedBigInteger { 1 })); break; default: ASSERT_NOT_REACHED(); } - auto new_value = Value(old_value.as_double() + op_result); reference.put(interpreter, new_value); if (interpreter.exception()) return {}; @@ -1420,6 +1435,11 @@ Value NumericLiteral::execute(Interpreter&) const return Value(m_value); } +Value BigIntLiteral::execute(Interpreter& interpreter) const +{ + return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1))); +} + Value BooleanLiteral::execute(Interpreter&) const { return Value(m_value); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 72f8972cc3..d764f6d07b 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -558,6 +558,22 @@ private: double m_value { 0 }; }; +class BigIntLiteral final : public Literal { +public: + explicit BigIntLiteral(String value) + : m_value(move(value)) + { + } + + virtual Value execute(Interpreter&) const override; + virtual void dump(int indent) const override; + +private: + virtual const char* class_name() const override { return "BigIntLiteral"; } + + String m_value; +}; + class StringLiteral final : public Literal { public: explicit StringLiteral(String value) diff --git a/Libraries/LibJS/CMakeLists.txt b/Libraries/LibJS/CMakeLists.txt index c170fe908a..e2de6c97b4 100644 --- a/Libraries/LibJS/CMakeLists.txt +++ b/Libraries/LibJS/CMakeLists.txt @@ -8,9 +8,13 @@ set(SOURCES Lexer.cpp MarkupGenerator.cpp Parser.cpp - Runtime/ArrayConstructor.cpp Runtime/Array.cpp + Runtime/ArrayConstructor.cpp Runtime/ArrayPrototype.cpp + Runtime/BigInt.cpp + Runtime/BigIntConstructor.cpp + Runtime/BigIntObject.cpp + Runtime/BigIntPrototype.cpp Runtime/BooleanConstructor.cpp Runtime/BooleanObject.cpp Runtime/BooleanPrototype.cpp @@ -65,4 +69,4 @@ set(SOURCES ) serenity_lib(LibJS js) -target_link_libraries(LibJS LibM LibCore) +target_link_libraries(LibJS LibM LibCore LibCrypto) diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 17c7953221..bea0352ae2 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -28,6 +28,7 @@ #define JS_ENUMERATE_NATIVE_OBJECTS \ __JS_ENUMERATE(Array, array, ArrayPrototype, ArrayConstructor) \ + __JS_ENUMERATE(BigIntObject, bigint, BigIntPrototype, BigIntConstructor) \ __JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor) \ __JS_ENUMERATE(Date, date, DatePrototype, DateConstructor) \ __JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor) \ @@ -55,6 +56,7 @@ namespace JS { class ASTNode; +class BigInt; class BoundFunction; class Cell; class DeferGC; diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 597e48c187..23890cadb4 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -348,37 +348,36 @@ Token Lexer::next() token_type = it->value; } } else if (is_numeric_literal_start()) { + token_type = TokenType::NumericLiteral; if (m_current_char == '0') { consume(); if (m_current_char == '.') { // decimal consume(); - while (isdigit(m_current_char)) { + while (isdigit(m_current_char)) consume(); - } - if (m_current_char == 'e' || m_current_char == 'E') { + if (m_current_char == 'e' || m_current_char == 'E') consume_exponent(); - } } else if (m_current_char == 'e' || m_current_char == 'E') { consume_exponent(); } else if (m_current_char == 'o' || m_current_char == 'O') { // octal consume(); - while (m_current_char >= '0' && m_current_char <= '7') { + while (m_current_char >= '0' && m_current_char <= '7') consume(); - } } else if (m_current_char == 'b' || m_current_char == 'B') { // binary consume(); - while (m_current_char == '0' || m_current_char == '1') { + while (m_current_char == '0' || m_current_char == '1') consume(); - } } else if (m_current_char == 'x' || m_current_char == 'X') { // hexadecimal consume(); - while (isxdigit(m_current_char)) { + while (isxdigit(m_current_char)) consume(); - } + } else if (m_current_char == 'n') { + consume(); + token_type = TokenType::BigIntLiteral; } else if (isdigit(m_current_char)) { // octal without 'O' prefix. Forbidden in 'strict mode' // FIXME: We need to make sure this produces a syntax error when in strict mode @@ -388,20 +387,21 @@ Token Lexer::next() } } else { // 1...9 or period - while (isdigit(m_current_char)) { + while (isdigit(m_current_char)) consume(); - } - if (m_current_char == '.') { + if (m_current_char == 'n') { consume(); - while (isdigit(m_current_char)) { + token_type = TokenType::BigIntLiteral; + } else { + if (m_current_char == '.') { consume(); + while (isdigit(m_current_char)) + consume(); } - } - if (m_current_char == 'e' || m_current_char == 'E') { - consume_exponent(); + if (m_current_char == 'e' || m_current_char == 'E') + consume_exponent(); } } - token_type = TokenType::NumericLiteral; } else if (m_current_char == '"' || m_current_char == '\'') { char stop_char = m_current_char; consume(); diff --git a/Libraries/LibJS/MarkupGenerator.cpp b/Libraries/LibJS/MarkupGenerator.cpp index 8836c7b069..ddea7711d6 100644 --- a/Libraries/LibJS/MarkupGenerator.cpp +++ b/Libraries/LibJS/MarkupGenerator.cpp @@ -217,6 +217,7 @@ MarkupGenerator::StyleType MarkupGenerator::style_type_for_token(Token token) case TokenType::UnterminatedTemplateLiteral: return StyleType::Invalid; case TokenType::NumericLiteral: + case TokenType::BigIntLiteral: return StyleType::Number; case TokenType::StringLiteral: case TokenType::TemplateLiteralStart: diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index d21b0171c2..7924c4913a 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -451,6 +451,8 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression() } case TokenType::NumericLiteral: return create_ast_node<NumericLiteral>(consume().double_value()); + case TokenType::BigIntLiteral: + return create_ast_node<BigIntLiteral>(consume().value()); case TokenType::BoolLiteral: return create_ast_node<BooleanLiteral>(consume().bool_value()); case TokenType::StringLiteral: @@ -547,7 +549,8 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() return match_identifier_name() || type == TokenType::BracketOpen || type == TokenType::StringLiteral - || type == TokenType::NumericLiteral; + || type == TokenType::NumericLiteral + || type == TokenType::BigIntLiteral; }; auto parse_property_key = [&]() -> NonnullRefPtr<Expression> { @@ -555,6 +558,9 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression() return parse_string_literal(consume()); } else if (match(TokenType::NumericLiteral)) { return create_ast_node<StringLiteral>(consume(TokenType::NumericLiteral).value()); + } else if (match(TokenType::BigIntLiteral)) { + auto value = consume(TokenType::BigIntLiteral).value(); + return create_ast_node<StringLiteral>(value.substring_view(0, value.length() - 1)); } else if (match(TokenType::BracketOpen)) { consume(TokenType::BracketOpen); auto result = parse_expression(0); @@ -1448,6 +1454,7 @@ bool Parser::match_expression() const auto type = m_parser_state.m_current_token.type(); return type == TokenType::BoolLiteral || type == TokenType::NumericLiteral + || type == TokenType::BigIntLiteral || type == TokenType::StringLiteral || type == TokenType::TemplateLiteralStart || type == TokenType::NullLiteral diff --git a/Libraries/LibJS/Runtime/BigInt.cpp b/Libraries/LibJS/Runtime/BigInt.cpp new file mode 100644 index 0000000000..9b62e82d9e --- /dev/null +++ b/Libraries/LibJS/Runtime/BigInt.cpp @@ -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. + */ + +#include <LibCrypto/BigInt/SignedBigInteger.h> +#include <LibJS/Interpreter.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<BigInt>(move(big_integer)); +} + +BigInt* js_bigint(Interpreter& interpreter, Crypto::SignedBigInteger big_integer) +{ + return js_bigint(interpreter.heap(), move(big_integer)); +} + +} diff --git a/Libraries/LibJS/Runtime/BigInt.h b/Libraries/LibJS/Runtime/BigInt.h new file mode 100644 index 0000000000..895fb28ee4 --- /dev/null +++ b/Libraries/LibJS/Runtime/BigInt.h @@ -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 <LibCrypto/BigInt/SignedBigInteger.h> +#include <LibJS/Runtime/BigInt.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::format("%sn", m_big_integer.to_base10().characters()); } + +private: + virtual const char* class_name() const override { return "BigInt"; } + + Crypto::SignedBigInteger m_big_integer; +}; + +BigInt* js_bigint(Heap&, Crypto::SignedBigInteger); +BigInt* js_bigint(Interpreter&, Crypto::SignedBigInteger); + +} diff --git a/Libraries/LibJS/Runtime/BigIntConstructor.cpp b/Libraries/LibJS/Runtime/BigIntConstructor.cpp new file mode 100644 index 0000000000..4dfb543f22 --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntConstructor.cpp @@ -0,0 +1,86 @@ +/* + * 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/Interpreter.h> +#include <LibJS/Runtime/BigIntConstructor.h> +#include <LibJS/Runtime/BigIntObject.h> +#include <LibJS/Runtime/Error.h> +#include <LibJS/Runtime/GlobalObject.h> + +namespace JS { + +BigIntConstructor::BigIntConstructor() + : NativeFunction("BigInt", *interpreter().global_object().function_prototype()) +{ + define_property("prototype", interpreter().global_object().bigint_prototype(), 0); + define_property("length", Value(1), Attribute::Configurable); + + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function("asIntN", as_int_n, 2, attr); + define_native_function("asUintN", as_uint_n, 2, attr); +} + +BigIntConstructor::~BigIntConstructor() +{ +} + +Value BigIntConstructor::call(Interpreter& interpreter) +{ + auto primitive = interpreter.argument(0).to_primitive(interpreter, Value::PreferredType::Number); + if (interpreter.exception()) + return {}; + if (primitive.is_number()) { + if (!primitive.is_integer()) { + interpreter.throw_exception<RangeError>("BigInt argument must be an integer"); + return {}; + } + return js_bigint(interpreter, Crypto::SignedBigInteger { primitive.as_i32() }); + } + auto* bigint = interpreter.argument(0).to_bigint(interpreter); + if (interpreter.exception()) + return {}; + return bigint; +} + +Value BigIntConstructor::construct(Interpreter& interpreter) +{ + interpreter.throw_exception<TypeError>("BigInt is not a constructor"); + return {}; +} + +Value BigIntConstructor::as_int_n(Interpreter&) +{ + TODO(); +} + +Value BigIntConstructor::as_uint_n(Interpreter&) +{ + TODO(); +} + +} diff --git a/Libraries/LibJS/Runtime/BigIntConstructor.h b/Libraries/LibJS/Runtime/BigIntConstructor.h new file mode 100644 index 0000000000..a012895afa --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntConstructor.h @@ -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/NativeFunction.h> + +namespace JS { + +class BigIntConstructor final : public NativeFunction { +public: + BigIntConstructor(); + virtual ~BigIntConstructor() 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 "BigIntConstructor"; } + + static Value as_int_n(Interpreter&); + static Value as_uint_n(Interpreter&); +}; + +} diff --git a/Libraries/LibJS/Runtime/BigIntObject.cpp b/Libraries/LibJS/Runtime/BigIntObject.cpp new file mode 100644 index 0000000000..046761e1c2 --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntObject.cpp @@ -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. + */ + +#include <LibJS/Heap/Heap.h> +#include <LibJS/Interpreter.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>(bigint, *global_object.bigint_prototype()); +} + +BigIntObject::BigIntObject(BigInt& bigint, Object& prototype) + : Object(&prototype) + , m_bigint(bigint) +{ +} + +BigIntObject::~BigIntObject() +{ +} + +void BigIntObject::visit_children(Cell::Visitor& visitor) +{ + Object::visit_children(visitor); + visitor.visit(&m_bigint); +} + +} diff --git a/Libraries/LibJS/Runtime/BigIntObject.h b/Libraries/LibJS/Runtime/BigIntObject.h new file mode 100644 index 0000000000..5c5a273400 --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntObject.h @@ -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 { +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_children(Visitor&) override; + virtual const char* class_name() const override { return "BigIntObject"; } + virtual bool is_bigint_object() const override { return true; } + + BigInt& m_bigint; +}; + +} diff --git a/Libraries/LibJS/Runtime/BigIntPrototype.cpp b/Libraries/LibJS/Runtime/BigIntPrototype.cpp new file mode 100644 index 0000000000..a271ca0b8c --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntPrototype.cpp @@ -0,0 +1,81 @@ +/* + * 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/Interpreter.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() + : Object(interpreter().global_object().object_prototype()) +{ + u8 attr = Attribute::Writable | Attribute::Configurable; + define_native_function("toString", to_string, 0, attr); + define_native_function("toLocaleString", to_locale_string, 0, attr); + define_native_function("valueOf", value_of, 0, attr); +} + +BigIntPrototype::~BigIntPrototype() +{ +} + +static BigIntObject* bigint_object_from(Interpreter& interpreter) +{ + auto* this_object = interpreter.this_value().to_object(interpreter); + if (!this_object) + return nullptr; + if (!this_object->is_bigint_object()) { + interpreter.throw_exception<TypeError>("Not a BigInt object"); + return nullptr; + } + return static_cast<BigIntObject*>(this_object); +} + +Value BigIntPrototype::to_string(Interpreter& interpreter) +{ + auto* bigint_object = bigint_object_from(interpreter); + if (!bigint_object) + return {}; + return js_string(interpreter, bigint_object->bigint().big_integer().to_base10()); +} + +Value BigIntPrototype::to_locale_string(Interpreter& interpreter) +{ + return to_string(interpreter); +} + +Value BigIntPrototype::value_of(Interpreter& interpreter) +{ + auto* bigint_object = bigint_object_from(interpreter); + if (!bigint_object) + return {}; + return bigint_object->value_of(); +} + +} diff --git a/Libraries/LibJS/Runtime/BigIntPrototype.h b/Libraries/LibJS/Runtime/BigIntPrototype.h new file mode 100644 index 0000000000..c2cb1914cb --- /dev/null +++ b/Libraries/LibJS/Runtime/BigIntPrototype.h @@ -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 BigIntPrototype final : public Object { +public: + BigIntPrototype(); + virtual ~BigIntPrototype() override; + +private: + virtual const char* class_name() const override { return "BigIntPrototype"; } + + static Value to_string(Interpreter&); + static Value to_locale_string(Interpreter&); + static Value value_of(Interpreter&); +}; + +} diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index f3aebccb0e..f5b621e9a5 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -29,6 +29,8 @@ #include <LibJS/Interpreter.h> #include <LibJS/Runtime/ArrayConstructor.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> @@ -97,6 +99,7 @@ void GlobalObject::initialize() define_property("Reflect", heap().allocate<ReflectObject>(), attr); add_constructor("Array", m_array_constructor, *m_array_prototype); + add_constructor("BigInt", m_bigint_constructor, *m_bigint_prototype); add_constructor("Boolean", m_boolean_constructor, *m_boolean_prototype); add_constructor("Date", m_date_constructor, *m_date_prototype); add_constructor("Error", m_error_constructor, *m_error_prototype); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 5da31021d0..bd127d2e74 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -105,6 +105,7 @@ public: virtual bool is_regexp_object() const { return false; } virtual bool is_string_object() const { return false; } virtual bool is_symbol_object() const { return false; } + virtual bool is_bigint_object() const { return false; } virtual const char* class_name() const override { return "Object"; } virtual void visit_children(Cell::Visitor&) override; diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index a1d3b0ece0..dacc2d31a3 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -1,5 +1,6 @@ /* * 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 @@ -28,10 +29,14 @@ #include <AK/String.h> #include <AK/StringBuilder.h> #include <AK/Utf8View.h> +#include <LibCrypto/BigInt/SignedBigInteger.h> +#include <LibCrypto/NumberTheory/ModularFunctions.h> #include <LibJS/Heap/Heap.h> #include <LibJS/Interpreter.h> #include <LibJS/Runtime/Accessor.h> #include <LibJS/Runtime/Array.h> +#include <LibJS/Runtime/BigInt.h> +#include <LibJS/Runtime/BigIntObject.h> #include <LibJS/Runtime/BooleanObject.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Function.h> @@ -42,10 +47,35 @@ #include <LibJS/Runtime/Symbol.h> #include <LibJS/Runtime/SymbolObject.h> #include <LibJS/Runtime/Value.h> +#include <ctype.h> #include <math.h> namespace JS { +static const Crypto::SignedBigInteger BIGINT_ZERO { 0 }; + +static bool is_valid_bigint_value(String string) +{ + string = string.trim_whitespace(); + if (string.length() > 1 && (string[0] == '-' || string[0] == '+')) + string = string.substring_view(1, string.length() - 1); + for (auto& ch : string) { + if (!isdigit(ch)) + return false; + } + return true; +} + +ALWAYS_INLINE bool both_number(const Value& lhs, const Value& rhs) +{ + return lhs.is_number() && rhs.is_number(); +} + +ALWAYS_INLINE bool both_bigint(const Value& lhs, const Value& rhs) +{ + return lhs.is_bigint() && rhs.is_bigint(); +} + bool Value::is_array() const { return is_object() && as_object().is_array(); @@ -83,6 +113,8 @@ String Value::to_string_without_side_effects() const return m_value.as_string->string(); case Type::Symbol: return m_value.as_symbol->to_string(); + case Type::BigInt: + return m_value.as_bigint->to_string(); case Type::Object: return String::format("[object %s]", as_object().class_name()); case Type::Accessor: @@ -124,6 +156,8 @@ String Value::to_string(Interpreter& interpreter) const case Type::Symbol: interpreter.throw_exception<TypeError>("Can't convert symbol to string"); return {}; + case Type::BigInt: + return m_value.as_bigint->big_integer().to_base10(); case Type::Object: { auto primitive_value = as_object().to_primitive(PreferredType::String); if (interpreter.exception()) @@ -150,6 +184,9 @@ bool Value::to_boolean() const case Type::String: return !m_value.as_string->string().is_empty(); case Type::Symbol: + return true; + case Type::BigInt: + return m_value.as_bigint->big_integer() != BIGINT_ZERO; case Type::Object: return true; default: @@ -179,6 +216,8 @@ Object* Value::to_object(Interpreter& interpreter) const return StringObject::create(interpreter.global_object(), *m_value.as_string); case Type::Symbol: return SymbolObject::create(interpreter.global_object(), *m_value.as_symbol); + case Type::BigInt: + return BigIntObject::create(interpreter.global_object(), *m_value.as_bigint); case Type::Object: return &const_cast<Object&>(as_object()); default: @@ -187,6 +226,16 @@ Object* Value::to_object(Interpreter& interpreter) const } } +Value Value::to_numeric(Interpreter& interpreter) const +{ + auto primitive = to_primitive(interpreter, Value::PreferredType::Number); + if (interpreter.exception()) + return {}; + if (primitive.is_bigint()) + return primitive; + return primitive.to_number(interpreter); +} + Value Value::to_number(Interpreter& interpreter) const { switch (m_type) { @@ -215,6 +264,9 @@ Value Value::to_number(Interpreter& interpreter) const case Type::Symbol: interpreter.throw_exception<TypeError>("Can't convert symbol to number"); return {}; + case Type::BigInt: + interpreter.throw_exception<TypeError>("Can't convert BigInt to number"); + return {}; case Type::Object: { auto primitive = m_value.as_object->to_primitive(PreferredType::Number); if (interpreter.exception()) @@ -226,6 +278,43 @@ Value Value::to_number(Interpreter& interpreter) const } } +BigInt* Value::to_bigint(Interpreter& interpreter) const +{ + auto primitive = to_primitive(interpreter, PreferredType::Number); + if (interpreter.exception()) + return nullptr; + switch (primitive.type()) { + case Type::Undefined: + interpreter.throw_exception<TypeError>("Can't convert undefined to BigInt"); + return nullptr; + case Type::Null: + interpreter.throw_exception<TypeError>("Can't convert null to BigInt"); + return nullptr; + case Type::Boolean: { + auto value = primitive.as_bool() ? 1 : 0; + return js_bigint(interpreter, Crypto::SignedBigInteger { value }); + } + case Type::BigInt: + return &primitive.as_bigint(); + case Type::Number: + interpreter.throw_exception<TypeError>("Can't convert number to BigInt"); + return {}; + case Type::String: { + auto& string = primitive.as_string().string(); + if (!is_valid_bigint_value(string)) { + interpreter.throw_exception<SyntaxError>(String::format("Invalid value for BigInt: %s", string.characters())); + return {}; + } + return js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(string.trim_whitespace())); + } + case Type::Symbol: + interpreter.throw_exception<TypeError>("Can't convert symbol to BigInt"); + return {}; + default: + ASSERT_NOT_REACHED(); + } +} + i32 Value::as_i32() const { return static_cast<i32>(as_double()); @@ -305,55 +394,70 @@ Value less_than_equals(Interpreter& interpreter, Value lhs, Value rhs) Value bitwise_and(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value((i32)lhs_number.as_double() & (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value((i32)lhs_numeric.as_double() & (i32)rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_and(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use bitwise AND operator with BigInt and other type"); + return {}; } Value bitwise_or(Interpreter& interpreter, Value lhs, Value rhs) { - bool lhs_invalid = lhs.is_undefined() || lhs.is_null() || lhs.is_nan() || lhs.is_infinity(); - bool rhs_invalid = rhs.is_undefined() || rhs.is_null() || rhs.is_nan() || rhs.is_infinity(); - - if (lhs_invalid && rhs_invalid) - return Value(0); - - if (lhs_invalid || rhs_invalid) - return lhs_invalid ? rhs.to_number(interpreter) : lhs.to_number(interpreter); - - if (!rhs.is_number() && !lhs.is_number()) - return Value(0); - - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value((i32)lhs_number.as_double() | (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) { + if (!lhs_numeric.is_finite_number() && !rhs_numeric.is_finite_number()) + return Value(0); + if (!lhs_numeric.is_finite_number()) + return rhs_numeric; + if (!rhs_numeric.is_finite_number()) + return lhs_numeric; + return Value((i32)lhs_numeric.as_double() | (i32)rhs_numeric.as_double()); + } + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_or(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use bitwise OR operator with BigInt and other type"); + return {}; } Value bitwise_xor(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value((i32)lhs_number.as_double() ^ (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value((i32)lhs_numeric.as_double() ^ (i32)rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().bitwise_xor(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use bitwise XOR operator with BigInt and other type"); + return {}; } Value bitwise_not(Interpreter& interpreter, Value lhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(~(i32)lhs_number.as_double()); + if (lhs_numeric.is_number()) + return Value(~(i32)lhs_numeric.as_double()); + auto big_integer_bitwise_not = lhs_numeric.as_bigint().big_integer(); + big_integer_bitwise_not = big_integer_bitwise_not.plus(Crypto::SignedBigInteger { 1 }); + big_integer_bitwise_not.negate(); + return js_bigint(interpreter, big_integer_bitwise_not); } Value unary_plus(Interpreter& interpreter, Value lhs) @@ -363,57 +467,80 @@ Value unary_plus(Interpreter& interpreter, Value lhs) Value unary_minus(Interpreter& interpreter, Value lhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (lhs_number.is_nan()) - return js_nan(); - return Value(-lhs_number.as_double()); + if (lhs_numeric.is_number()) { + if (lhs_numeric.is_nan()) + return js_nan(); + return Value(-lhs_numeric.as_double()); + } + if (lhs_numeric.as_bigint().big_integer() == BIGINT_ZERO) + return js_bigint(interpreter, BIGINT_ZERO); + auto big_integer_negated = lhs_numeric.as_bigint().big_integer(); + big_integer_negated.negate(); + return js_bigint(interpreter, big_integer_negated); } Value left_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!lhs_number.is_finite_number()) - return Value(0); - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!rhs_number.is_finite_number()) - return lhs_number; - return Value((i32)lhs_number.as_double() << (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) { + if (!lhs_numeric.is_finite_number()) + return Value(0); + if (!rhs_numeric.is_finite_number()) + return lhs_numeric; + return Value((i32)lhs_numeric.as_double() << (i32)rhs_numeric.as_double()); + } + if (both_bigint(lhs_numeric, rhs_numeric)) + TODO(); + interpreter.throw_exception<TypeError>("Can't use left-shift operator with BigInt and other type"); + return {}; } Value right_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!lhs_number.is_finite_number()) - return Value(0); - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!rhs_number.is_finite_number()) - return lhs_number; - return Value((i32)lhs_number.as_double() >> (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) { + if (!lhs_numeric.is_finite_number()) + return Value(0); + if (!rhs_numeric.is_finite_number()) + return lhs_numeric; + return Value((i32)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double()); + } + if (both_bigint(lhs_numeric, rhs_numeric)) + TODO(); + interpreter.throw_exception<TypeError>("Can't use right-shift operator with BigInt and other type"); + return {}; } Value unsigned_right_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!lhs_number.is_finite_number()) - return Value(0); - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (!rhs_number.is_finite_number()) - return lhs_number; - return Value((unsigned)lhs_number.as_double() >> (i32)rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) { + if (!lhs_numeric.is_finite_number()) + return Value(0); + if (!rhs_numeric.is_finite_number()) + return lhs_numeric; + return Value((unsigned)lhs_numeric.as_double() >> (i32)rhs_numeric.as_double()); + } + interpreter.throw_exception<TypeError>("Can't use unsigned right-shift operator with BigInt"); + return {}; } Value add(Interpreter& interpreter, Value lhs, Value rhs) @@ -438,73 +565,104 @@ Value add(Interpreter& interpreter, Value lhs, Value rhs) return js_string(interpreter, builder.to_string()); } - auto lhs_number = lhs_primitive.to_number(interpreter); + auto lhs_numeric = lhs_primitive.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs_primitive.to_number(interpreter); + auto rhs_numeric = rhs_primitive.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(lhs_number.as_double() + rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value(lhs_numeric.as_double() + rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().plus(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use addition operator with BigInt and other type"); + return {}; } Value sub(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(lhs_number.as_double() - rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value(lhs_numeric.as_double() - rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().minus(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use subtraction operator with BigInt and other type"); + return {}; } Value mul(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(lhs_number.as_double() * rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value(lhs_numeric.as_double() * rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().multiplied_by(rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use multiplication operator with BigInt and other type"); + return {}; } Value div(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(lhs_number.as_double() / rhs_number.as_double()); + if (both_number(lhs_numeric, rhs_numeric)) + return Value(lhs_numeric.as_double() / rhs_numeric.as_double()); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient); + interpreter.throw_exception<TypeError>("Can't use division operator with BigInt and other type"); + return {}; } Value mod(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - if (lhs_number.is_nan() || rhs_number.is_nan()) - return js_nan(); - auto index = lhs_number.as_double(); - auto period = rhs_number.as_double(); - auto trunc = (double)(i32)(index / period); - return Value(index - trunc * period); + if (both_number(lhs_numeric, rhs_numeric)) { + if (lhs_numeric.is_nan() || rhs_numeric.is_nan()) + return js_nan(); + auto index = lhs_numeric.as_double(); + auto period = rhs_numeric.as_double(); + auto trunc = (double)(i32)(index / period); + return Value(index - trunc * period); + } + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder); + interpreter.throw_exception<TypeError>("Can't use modulo operator with BigInt and other type"); + return {}; } Value exp(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(interpreter); + auto lhs_numeric = lhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto rhs_number = rhs.to_number(interpreter); + auto rhs_numeric = rhs.to_numeric(interpreter); if (interpreter.exception()) return {}; - return Value(pow(lhs_number.as_double(), rhs_number.as_double())); + if (both_number(lhs_numeric, rhs_numeric)) + return Value(pow(lhs_numeric.as_double(), rhs_numeric.as_double())); + if (both_bigint(lhs_numeric, rhs_numeric)) + return js_bigint(interpreter, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer())); + interpreter.throw_exception<TypeError>("Can't use exponentiation operator with BigInt and other type"); + return {}; } Value in(Interpreter& interpreter, Value lhs, Value rhs) @@ -547,6 +705,14 @@ bool same_value(Interpreter& interpreter, Value lhs, Value rhs) return lhs.as_double() == rhs.as_double(); } + if (lhs.is_bigint()) { + auto lhs_big_integer = lhs.as_bigint().big_integer(); + auto rhs_big_integer = rhs.as_bigint().big_integer(); + if (lhs_big_integer == BIGINT_ZERO && rhs_big_integer == BIGINT_ZERO && lhs_big_integer.is_negative() != rhs_big_integer.is_negative()) + return false; + return lhs_big_integer == rhs_big_integer; + } + return same_value_non_numeric(interpreter, lhs, rhs); } @@ -558,17 +724,18 @@ bool same_value_zero(Interpreter& interpreter, Value lhs, Value rhs) if (lhs.is_number()) { if (lhs.is_nan() && rhs.is_nan()) return true; - if ((lhs.is_positive_zero() || lhs.is_negative_zero()) && (rhs.is_positive_zero() || rhs.is_negative_zero())) - return true; return lhs.as_double() == rhs.as_double(); } + if (lhs.is_bigint()) + return lhs.as_bigint().big_integer() == rhs.as_bigint().big_integer(); + return same_value_non_numeric(interpreter, lhs, rhs); } bool same_value_non_numeric(Interpreter&, Value lhs, Value rhs) { - ASSERT(!lhs.is_number()); + ASSERT(!lhs.is_number() && !lhs.is_bigint()); ASSERT(lhs.type() == rhs.type()); switch (lhs.type()) { @@ -598,11 +765,12 @@ bool strict_eq(Interpreter& interpreter, Value lhs, Value rhs) return false; if (lhs.as_double() == rhs.as_double()) return true; - if ((lhs.is_positive_zero() || lhs.is_negative_zero()) && (rhs.is_positive_zero() || rhs.is_negative_zero())) - return true; return false; } + if (lhs.is_bigint()) + return lhs.as_bigint().big_integer() == rhs.as_bigint().big_integer(); + return same_value_non_numeric(interpreter, lhs, rhs); } @@ -620,25 +788,46 @@ bool abstract_eq(Interpreter& interpreter, Value lhs, Value rhs) if (lhs.is_string() && rhs.is_number()) return abstract_eq(interpreter, lhs.to_number(interpreter), rhs); + if (lhs.is_bigint() && rhs.is_string()) { + auto& rhs_string = rhs.as_string().string(); + if (!is_valid_bigint_value(rhs_string)) + return false; + return abstract_eq(interpreter, lhs, js_bigint(interpreter, Crypto::SignedBigInteger::from_base10(rhs_string))); + } + + if (lhs.is_string() && rhs.is_bigint()) + return abstract_eq(interpreter, rhs, lhs); + if (lhs.is_boolean()) return abstract_eq(interpreter, lhs.to_number(interpreter), rhs); if (rhs.is_boolean()) return abstract_eq(interpreter, lhs, rhs.to_number(interpreter)); - if ((lhs.is_string() || lhs.is_number() || lhs.is_symbol()) && rhs.is_object()) + if ((lhs.is_string() || lhs.is_number() || lhs.is_bigint() || lhs.is_symbol()) && rhs.is_object()) return abstract_eq(interpreter, lhs, rhs.to_primitive(interpreter)); - if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || rhs.is_symbol())) + if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || lhs.is_bigint() || rhs.is_symbol())) return abstract_eq(interpreter, lhs.to_primitive(interpreter), rhs); + if ((lhs.is_bigint() && rhs.is_number()) || (lhs.is_number() && rhs.is_bigint())) { + if (lhs.is_nan() || lhs.is_infinity() || rhs.is_nan() || rhs.is_infinity()) + return false; + if ((lhs.is_number() && !lhs.is_integer()) || (rhs.is_number() && !rhs.is_integer())) + return false; + if (lhs.is_number()) + return Crypto::SignedBigInteger { lhs.as_i32() } == rhs.as_bigint().big_integer(); + else + return Crypto::SignedBigInteger { rhs.as_i32() } == lhs.as_bigint().big_integer(); + } + return false; } TriState abstract_relation(Interpreter& interpreter, bool left_first, Value lhs, Value rhs) { - Value x_primitive = {}; - Value y_primitive = {}; + Value x_primitive; + Value y_primitive; if (left_first) { x_primitive = lhs.to_primitive(interpreter, Value::PreferredType::Number); @@ -681,12 +870,30 @@ TriState abstract_relation(Interpreter& interpreter, bool left_first, Value lhs, ASSERT_NOT_REACHED(); } - // FIXME add BigInt cases here once we have BigInt + if (x_primitive.is_bigint() && y_primitive.is_string()) { + auto& y_string = y_primitive.as_string().string(); + if (!is_valid_bigint_value(y_string)) + return TriState::Unknown; + if (x_primitive.as_bigint().big_integer() < Crypto::SignedBigInteger::from_base10(y_string)) + return TriState::True; + else + return TriState::False; + } - auto x_numeric = x_primitive.to_number(interpreter); + if (x_primitive.is_string() && y_primitive.is_bigint()) { + auto& x_string = x_primitive.as_string().string(); + if (!is_valid_bigint_value(x_string)) + return TriState::Unknown; + if (Crypto::SignedBigInteger::from_base10(x_string) < y_primitive.as_bigint().big_integer()) + return TriState::True; + else + return TriState::False; + } + + auto x_numeric = x_primitive.to_numeric(interpreter); if (interpreter.exception()) return {}; - auto y_numeric = y_primitive.to_number(interpreter); + auto y_numeric = y_primitive.to_numeric(interpreter); if (interpreter.exception()) return {}; @@ -699,10 +906,33 @@ TriState abstract_relation(Interpreter& interpreter, bool left_first, Value lhs, if (x_numeric.is_negative_infinity() || y_numeric.is_positive_infinity()) return TriState::True; - auto x_value = x_numeric.as_double(); - auto y_value = y_numeric.as_double(); + if (x_numeric.is_number() && y_numeric.is_number()) { + if (x_numeric.as_double() < y_numeric.as_double()) + return TriState::True; + else + return TriState::False; + } - if (x_value < y_value) + if (x_numeric.is_bigint() && y_numeric.is_bigint()) { + if (x_numeric.as_bigint().big_integer() < y_numeric.as_bigint().big_integer()) + return TriState::True; + else + return TriState::False; + } + + ASSERT((x_numeric.is_number() && y_numeric.is_bigint()) || (x_numeric.is_bigint() && y_numeric.is_number())); + + bool x_lower_than_y; + if (x_numeric.is_number()) { + x_lower_than_y = x_numeric.is_integer() + ? Crypto::SignedBigInteger { x_numeric.as_i32() } < y_numeric.as_bigint().big_integer() + : (Crypto::SignedBigInteger { x_numeric.as_i32() } < y_numeric.as_bigint().big_integer() || Crypto::SignedBigInteger { x_numeric.as_i32() + 1 } < y_numeric.as_bigint().big_integer()); + } else { + x_lower_than_y = y_numeric.is_integer() + ? x_numeric.as_bigint().big_integer() < Crypto::SignedBigInteger { y_numeric.as_i32() } + : (x_numeric.as_bigint().big_integer() < Crypto::SignedBigInteger { y_numeric.as_i32() } || x_numeric.as_bigint().big_integer() < Crypto::SignedBigInteger { y_numeric.as_i32() + 1 }); + } + if (x_lower_than_y) return TriState::True; else return TriState::False; diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index 0b252e2c6f..b7a3d712eb 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -31,7 +31,6 @@ #include <AK/LogStream.h> #include <AK/Types.h> #include <LibJS/Forward.h> -#include <LibJS/Runtime/Symbol.h> #include <math.h> // 2 ** 53 - 1 @@ -51,6 +50,7 @@ public: Boolean, Symbol, Accessor, + BigInt, }; enum class PreferredType { @@ -68,6 +68,7 @@ public: bool is_boolean() const { return m_type == Type::Boolean; } bool is_symbol() const { return m_type == Type::Symbol; } bool is_accessor() const { return m_type == Type::Accessor; }; + bool is_bigint() const { return m_type == Type::BigInt; }; bool is_cell() const { return is_string() || is_accessor() || is_object(); } bool is_array() const; bool is_function() const; @@ -140,6 +141,12 @@ public: m_value.as_accessor = accessor; } + Value(BigInt* bigint) + : m_type(Type::BigInt) + { + m_value.as_bigint = bigint; + } + explicit Value(Type type) : m_type(type) { @@ -207,6 +214,12 @@ public: return *m_value.as_accessor; } + BigInt& as_bigint() + { + ASSERT(is_bigint()); + return *m_value.as_bigint; + } + Function& as_function(); i32 as_i32() const; @@ -216,7 +229,9 @@ public: PrimitiveString* to_primitive_string(Interpreter&); Value to_primitive(Interpreter&, PreferredType preferred_type = PreferredType::Default) const; Object* to_object(Interpreter&) const; + Value to_numeric(Interpreter&) const; Value to_number(Interpreter&) const; + BigInt* to_bigint(Interpreter&) const; double to_double(Interpreter&) const; i32 to_i32(Interpreter&) const; size_t to_size_t(Interpreter&) const; @@ -242,6 +257,7 @@ private: Object* as_object; Cell* as_cell; Accessor* as_accessor; + BigInt* as_bigint; } m_value; }; diff --git a/Libraries/LibJS/Tests/BigInt.asIntN.js b/Libraries/LibJS/Tests/BigInt.asIntN.js new file mode 100644 index 0000000000..82deab3be4 --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.asIntN.js @@ -0,0 +1,9 @@ +load("test-common.js"); + +try { + assert(BigInt.asIntN.length === 2); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/BigInt.asUintN.js b/Libraries/LibJS/Tests/BigInt.asUintN.js new file mode 100644 index 0000000000..d63b261ce3 --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.asUintN.js @@ -0,0 +1,9 @@ +load("test-common.js"); + +try { + assert(BigInt.asUintN.length === 2); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/BigInt.js b/Libraries/LibJS/Tests/BigInt.js new file mode 100644 index 0000000000..e24f34de90 --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.js @@ -0,0 +1,62 @@ +load("test-common.js"); + +try { + assert(BigInt.length === 1); + assert(BigInt.name === "BigInt"); + + assert(BigInt(0) === 0n); + assert(BigInt(1) === 1n); + assert(BigInt(+1) === 1n); + assert(BigInt(-1) === -1n); + assert(BigInt("") === 0n); + assert(BigInt("0") === 0n); + assert(BigInt("1") === 1n); + assert(BigInt("+1") === 1n); + assert(BigInt("-1") === -1n); + assert(BigInt("-1") === -1n); + assert(BigInt([]) === 0n); + assert(BigInt("42") === 42n); + assert(BigInt(" \n 00100 \n ") === 100n); + assert(BigInt(123n) === 123n); + assert(BigInt("3323214327642987348732109829832143298746432437532197321") === 3323214327642987348732109829832143298746432437532197321n); + + assertThrowsError(() => { + new BigInt(); + }, { + error: TypeError, + message: "BigInt is not a constructor" + }); + + [null, undefined, Symbol()].forEach(value => { + assertThrowsError(() => { + BigInt(value); + }, { + error: TypeError, + message: typeof value === "symbol" + ? "Can't convert symbol to BigInt" + : `Can't convert ${value} to BigInt` + }); + }); + + ["foo", "123n", "1+1", {}, function () { }].forEach(value => { + assertThrowsError(() => { + BigInt(value); + }, { + error: SyntaxError, + message: `Invalid value for BigInt: ${value}` + }); + }); + + [1.23, Infinity, -Infinity, NaN].forEach(value => { + assertThrowsError(() => { + BigInt(value); + }, { + error: RangeError, + message: "BigInt argument must be an integer" + }); + }); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/BigInt.prototype.toLocaleString.js b/Libraries/LibJS/Tests/BigInt.prototype.toLocaleString.js new file mode 100644 index 0000000000..bbde955404 --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.prototype.toLocaleString.js @@ -0,0 +1,18 @@ +load("test-common.js"); + +try { + assert(BigInt.prototype.toLocaleString.length === 0); + + assertThrowsError(() => { + BigInt.prototype.toLocaleString.call("foo"); + }, { + error: TypeError, + message: "Not a BigInt object" + }); + + assert(BigInt(123).toLocaleString() === "123"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/BigInt.prototype.toString.js b/Libraries/LibJS/Tests/BigInt.prototype.toString.js new file mode 100644 index 0000000000..8729784ebc --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.prototype.toString.js @@ -0,0 +1,18 @@ +load("test-common.js"); + +try { + assert(BigInt.prototype.toString.length === 0); + + assertThrowsError(() => { + BigInt.prototype.toString.call("foo"); + }, { + error: TypeError, + message: "Not a BigInt object" + }); + + assert(BigInt(123).toString() === "123"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/BigInt.prototype.valueOf.js b/Libraries/LibJS/Tests/BigInt.prototype.valueOf.js new file mode 100644 index 0000000000..b3bd798eaa --- /dev/null +++ b/Libraries/LibJS/Tests/BigInt.prototype.valueOf.js @@ -0,0 +1,20 @@ +load("test-common.js"); + +try { + assert(BigInt.prototype.valueOf.length === 0); + + assertThrowsError(() => { + BigInt.prototype.valueOf.call("foo"); + }, { + error: TypeError, + message: "Not a BigInt object" + }); + + assert(typeof BigInt(123).valueOf() === "bigint"); + // FIXME: Uncomment once we support Object() with argument + // assert(typeof Object(123n).valueOf() === "bigint"); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/bigint-basic.js b/Libraries/LibJS/Tests/bigint-basic.js new file mode 100644 index 0000000000..896ebae3c0 --- /dev/null +++ b/Libraries/LibJS/Tests/bigint-basic.js @@ -0,0 +1,68 @@ +load("test-common.js"); + +try { + var bigint = 123n; + + assert(typeof bigint === "bigint"); + assert(-bigint === -123n); + assert("" + bigint === "123") + + assertThrowsError(() => { + +bigint; + }, { + error: TypeError, + message: "Can't convert BigInt to number" + }); + + assert(12n + 34n === 46n); + assert(12n - 34n === -22n); + assert(8n * 12n === 96n); + assert(123n / 10n === 12n); + assert(2n ** 3n === 8n); + assert(5n % 3n === 2n); + assert(45977665298704210987n + 714320987142450987412098743217984576n / 4598741987421098765327980n * 987498743n === 199365500239020623962n); + + assert((12n & 5n) === 4n); + assert((1n | 2n) === 3n); + assert((5n ^ 3n) === 6n); + assert(~1n === -2n); + + bigint = 1n; + assert(bigint++ === 1n); + assert(bigint === 2n); + assert(bigint-- === 2n); + assert(bigint === 1n); + assert(++bigint === 2n); + assert(bigint === 2n); + assert(--bigint === 1n); + assert(bigint === 1n); + + + assert((1n == 1n) === true); + assert((1n == 1) === true); + assert((1 == 1n) === true); + assert((1n == 1.23) === false); + assert((1.23 == 1n) === false); + + assert((1n != 1n) === false); + assert((1n != 1) === false); + assert((1 != 1n) === false); + assert((1n != 1.23) === true); + assert((1.23 != 1n) === true); + + assert((1n === 1n) === true); + assert((1n === 1) == false); + assert((1 === 1n) === false); + assert((1n === 1.23) === false); + assert((1.23 === 1n) === false); + + assert((1n !== 1n) === false); + assert((1n !== 1) === true); + assert((1 !== 1n) === true); + assert((1n !== 1.23) === true); + assert((1.23 !== 1n) === true); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/bigint-number-mix-errors.js b/Libraries/LibJS/Tests/bigint-number-mix-errors.js new file mode 100644 index 0000000000..382201b54b --- /dev/null +++ b/Libraries/LibJS/Tests/bigint-number-mix-errors.js @@ -0,0 +1,82 @@ +load("test-common.js"); + +try { + [1, null, undefined].forEach(value => { + assertThrowsError(() => { + 1n + value; + }, { + error: TypeError, + message: "Can't use addition operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n - value; + }, { + error: TypeError, + message: "Can't use subtraction operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n * value; + }, { + error: TypeError, + message: "Can't use multiplication operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n / value; + }, { + error: TypeError, + message: "Can't use division operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n % value; + }, { + error: TypeError, + message: "Can't use modulo operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n ** value; + }, { + error: TypeError, + message: "Can't use exponentiation operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n | value; + }, { + error: TypeError, + message: "Can't use bitwise OR operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n & value; + }, { + error: TypeError, + message: "Can't use bitwise AND operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n ^ value; + }, { + error: TypeError, + message: "Can't use bitwise XOR operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n << value; + }, { + error: TypeError, + message: "Can't use left-shift operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n >> value; + }, { + error: TypeError, + message: "Can't use right-shift operator with BigInt and other type" + }); + assertThrowsError(() => { + 1n >>> value; + }, { + error: TypeError, + message: "Can't use unsigned right-shift operator with BigInt" + }); + }); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/binary-relational.js b/Libraries/LibJS/Tests/binary-relational.js index 55884dd170..01397d5147 100644 --- a/Libraries/LibJS/Tests/binary-relational.js +++ b/Libraries/LibJS/Tests/binary-relational.js @@ -1,531 +1,735 @@ load("test-common.js"); try { - const vals = [ - 1, - 2, - [], - [1], - [2], - [1, 2], - "foo", - "fooo", - "🔥", - "❤️", - "bar", - {}, - { a: 1 }, - { a: 2 }, - { b: 1 }, - true, - false, - undefined, - null, - NaN, - +Infinity, - -Infinity, - ]; + const vals = [ + 1, + 2, + 1.23, + 2.34567, + 1n, + 2n, + [], + [1], + [2], + [1, 2], + "foo", + "fooo", + "🔥", + "❤️", + "bar", + {}, + { a: 1 }, + { a: 2 }, + { b: 1 }, + true, + false, + undefined, + null, + NaN, + +Infinity, + -Infinity, + ]; - // Each row contains: x_index, y_index, (x < y), (x > y), (x <= y), (x >= y) - // where x = vals[x_index], y = vals[y_index] - const table = [ - [0, 0, false, false, true, true], - [0, 1, true, false, true, false], - [0, 2, false, true, false, true], - [0, 3, false, false, true, true], - [0, 4, true, false, true, false], - [0, 5, false, false, false, false], - [0, 6, false, false, false, false], - [0, 7, false, false, false, false], - [0, 8, false, false, false, false], - [0, 9, false, false, false, false], - [0, 10, false, false, false, false], - [0, 11, false, false, false, false], - [0, 12, false, false, false, false], - [0, 13, false, false, false, false], - [0, 14, false, false, false, false], - [0, 15, false, false, true, true], - [0, 16, false, true, false, true], - [0, 17, false, false, false, false], - [0, 18, false, true, false, true], - [0, 19, false, false, false, false], - [0, 20, true, false, true, false], - [0, 21, false, true, false, true], - [1, 0, false, true, false, true], - [1, 1, false, false, true, true], - [1, 2, false, true, false, true], - [1, 3, false, true, false, true], - [1, 4, false, false, true, true], - [1, 5, false, false, false, false], - [1, 6, false, false, false, false], - [1, 7, false, false, false, false], - [1, 8, false, false, false, false], - [1, 9, false, false, false, false], - [1, 10, false, false, false, false], - [1, 11, false, false, false, false], - [1, 12, false, false, false, false], - [1, 13, false, false, false, false], - [1, 14, false, false, false, false], - [1, 15, false, true, false, true], - [1, 16, false, true, false, true], - [1, 17, false, false, false, false], - [1, 18, false, true, false, true], - [1, 19, false, false, false, false], - [1, 20, true, false, true, false], - [1, 21, false, true, false, true], - [2, 0, true, false, true, false], - [2, 1, true, false, true, false], - [2, 2, false, false, true, true], - [2, 3, true, false, true, false], - [2, 4, true, false, true, false], - [2, 5, true, false, true, false], - [2, 6, true, false, true, false], - [2, 7, true, false, true, false], - [2, 8, true, false, true, false], - [2, 9, true, false, true, false], - [2, 10, true, false, true, false], - [2, 11, true, false, true, false], - [2, 12, true, false, true, false], - [2, 13, true, false, true, false], - [2, 14, true, false, true, false], - [2, 15, true, false, true, false], - [2, 16, false, false, true, true], - [2, 17, false, false, false, false], - [2, 18, false, false, true, true], - [2, 19, false, false, false, false], - [2, 20, true, false, true, false], - [2, 21, false, true, false, true], - [3, 0, false, false, true, true], - [3, 1, true, false, true, false], - [3, 2, false, true, false, true], - [3, 3, false, false, true, true], - [3, 4, true, false, true, false], - [3, 5, true, false, true, false], - [3, 6, true, false, true, false], - [3, 7, true, false, true, false], - [3, 8, true, false, true, false], - [3, 9, true, false, true, false], - [3, 10, true, false, true, false], - [3, 11, true, false, true, false], - [3, 12, true, false, true, false], - [3, 13, true, false, true, false], - [3, 14, true, false, true, false], - [3, 15, false, false, true, true], - [3, 16, false, true, false, true], - [3, 17, false, false, false, false], - [3, 18, false, true, false, true], - [3, 19, false, false, false, false], - [3, 20, true, false, true, false], - [3, 21, false, true, false, true], - [4, 0, false, true, false, true], - [4, 1, false, false, true, true], - [4, 2, false, true, false, true], - [4, 3, false, true, false, true], - [4, 4, false, false, true, true], - [4, 5, false, true, false, true], - [4, 6, true, false, true, false], - [4, 7, true, false, true, false], - [4, 8, true, false, true, false], - [4, 9, true, false, true, false], - [4, 10, true, false, true, false], - [4, 11, true, false, true, false], - [4, 12, true, false, true, false], - [4, 13, true, false, true, false], - [4, 14, true, false, true, false], - [4, 15, false, true, false, true], - [4, 16, false, true, false, true], - [4, 17, false, false, false, false], - [4, 18, false, true, false, true], - [4, 19, false, false, false, false], - [4, 20, true, false, true, false], - [4, 21, false, true, false, true], - [5, 0, false, false, false, false], - [5, 1, false, false, false, false], - [5, 2, false, true, false, true], - [5, 3, false, true, false, true], - [5, 4, true, false, true, false], - [5, 5, false, false, true, true], - [5, 6, true, false, true, false], - [5, 7, true, false, true, false], - [5, 8, true, false, true, false], - [5, 9, true, false, true, false], - [5, 10, true, false, true, false], - [5, 11, true, false, true, false], - [5, 12, true, false, true, false], - [5, 13, true, false, true, false], - [5, 14, true, false, true, false], - [5, 15, false, false, false, false], - [5, 16, false, false, false, false], - [5, 17, false, false, false, false], - [5, 18, false, false, false, false], - [5, 19, false, false, false, false], - [5, 20, false, false, false, false], - [5, 21, false, false, false, false], - [6, 0, false, false, false, false], - [6, 1, false, false, false, false], - [6, 2, false, true, false, true], - [6, 3, false, true, false, true], - [6, 4, false, true, false, true], - [6, 5, false, true, false, true], - [6, 6, false, false, true, true], - [6, 7, true, false, true, false], - [6, 8, true, false, true, false], - [6, 9, true, false, true, false], - [6, 10, false, true, false, true], - [6, 11, false, true, false, true], - [6, 12, false, true, false, true], - [6, 13, false, true, false, true], - [6, 14, false, true, false, true], - [6, 15, false, false, false, false], - [6, 16, false, false, false, false], - [6, 17, false, false, false, false], - [6, 18, false, false, false, false], - [6, 19, false, false, false, false], - [6, 20, false, false, false, false], - [6, 21, false, false, false, false], - [7, 0, false, false, false, false], - [7, 1, false, false, false, false], - [7, 2, false, true, false, true], - [7, 3, false, true, false, true], - [7, 4, false, true, false, true], - [7, 5, false, true, false, true], - [7, 6, false, true, false, true], - [7, 7, false, false, true, true], - [7, 8, true, false, true, false], - [7, 9, true, false, true, false], - [7, 10, false, true, false, true], - [7, 11, false, true, false, true], - [7, 12, false, true, false, true], - [7, 13, false, true, false, true], - [7, 14, false, true, false, true], - [7, 15, false, false, false, false], - [7, 16, false, false, false, false], - [7, 17, false, false, false, false], - [7, 18, false, false, false, false], - [7, 19, false, false, false, false], - [7, 20, false, false, false, false], - [7, 21, false, false, false, false], - [8, 0, false, false, false, false], - [8, 1, false, false, false, false], - [8, 2, false, true, false, true], - [8, 3, false, true, false, true], - [8, 4, false, true, false, true], - [8, 5, false, true, false, true], - [8, 6, false, true, false, true], - [8, 7, false, true, false, true], - [8, 8, false, false, true, true], - [8, 9, false, true, false, true], - [8, 10, false, true, false, true], - [8, 11, false, true, false, true], - [8, 12, false, true, false, true], - [8, 13, false, true, false, true], - [8, 14, false, true, false, true], - [8, 15, false, false, false, false], - [8, 16, false, false, false, false], - [8, 17, false, false, false, false], - [8, 18, false, false, false, false], - [8, 19, false, false, false, false], - [8, 20, false, false, false, false], - [8, 21, false, false, false, false], - [9, 0, false, false, false, false], - [9, 1, false, false, false, false], - [9, 2, false, true, false, true], - [9, 3, false, true, false, true], - [9, 4, false, true, false, true], - [9, 5, false, true, false, true], - [9, 6, false, true, false, true], - [9, 7, false, true, false, true], - [9, 8, true, false, true, false], - [9, 9, false, false, true, true], - [9, 10, false, true, false, true], - [9, 11, false, true, false, true], - [9, 12, false, true, false, true], - [9, 13, false, true, false, true], - [9, 14, false, true, false, true], - [9, 15, false, false, false, false], - [9, 16, false, false, false, false], - [9, 17, false, false, false, false], - [9, 18, false, false, false, false], - [9, 19, false, false, false, false], - [9, 20, false, false, false, false], - [9, 21, false, false, false, false], - [10, 0, false, false, false, false], - [10, 1, false, false, false, false], - [10, 2, false, true, false, true], - [10, 3, false, true, false, true], - [10, 4, false, true, false, true], - [10, 5, false, true, false, true], - [10, 6, true, false, true, false], - [10, 7, true, false, true, false], - [10, 8, true, false, true, false], - [10, 9, true, false, true, false], - [10, 10, false, false, true, true], - [10, 11, false, true, false, true], - [10, 12, false, true, false, true], - [10, 13, false, true, false, true], - [10, 14, false, true, false, true], - [10, 15, false, false, false, false], - [10, 16, false, false, false, false], - [10, 17, false, false, false, false], - [10, 18, false, false, false, false], - [10, 19, false, false, false, false], - [10, 20, false, false, false, false], - [10, 21, false, false, false, false], - [11, 0, false, false, false, false], - [11, 1, false, false, false, false], - [11, 2, false, true, false, true], - [11, 3, false, true, false, true], - [11, 4, false, true, false, true], - [11, 5, false, true, false, true], - [11, 6, true, false, true, false], - [11, 7, true, false, true, false], - [11, 8, true, false, true, false], - [11, 9, true, false, true, false], - [11, 10, true, false, true, false], - [11, 11, false, false, true, true], - [11, 12, false, false, true, true], - [11, 13, false, false, true, true], - [11, 14, false, false, true, true], - [11, 15, false, false, false, false], - [11, 16, false, false, false, false], - [11, 17, false, false, false, false], - [11, 18, false, false, false, false], - [11, 19, false, false, false, false], - [11, 20, false, false, false, false], - [11, 21, false, false, false, false], - [12, 0, false, false, false, false], - [12, 1, false, false, false, false], - [12, 2, false, true, false, true], - [12, 3, false, true, false, true], - [12, 4, false, true, false, true], - [12, 5, false, true, false, true], - [12, 6, true, false, true, false], - [12, 7, true, false, true, false], - [12, 8, true, false, true, false], - [12, 9, true, false, true, false], - [12, 10, true, false, true, false], - [12, 11, false, false, true, true], - [12, 12, false, false, true, true], - [12, 13, false, false, true, true], - [12, 14, false, false, true, true], - [12, 15, false, false, false, false], - [12, 16, false, false, false, false], - [12, 17, false, false, false, false], - [12, 18, false, false, false, false], - [12, 19, false, false, false, false], - [12, 20, false, false, false, false], - [12, 21, false, false, false, false], - [13, 0, false, false, false, false], - [13, 1, false, false, false, false], - [13, 2, false, true, false, true], - [13, 3, false, true, false, true], - [13, 4, false, true, false, true], - [13, 5, false, true, false, true], - [13, 6, true, false, true, false], - [13, 7, true, false, true, false], - [13, 8, true, false, true, false], - [13, 9, true, false, true, false], - [13, 10, true, false, true, false], - [13, 11, false, false, true, true], - [13, 12, false, false, true, true], - [13, 13, false, false, true, true], - [13, 14, false, false, true, true], - [13, 15, false, false, false, false], - [13, 16, false, false, false, false], - [13, 17, false, false, false, false], - [13, 18, false, false, false, false], - [13, 19, false, false, false, false], - [13, 20, false, false, false, false], - [13, 21, false, false, false, false], - [14, 0, false, false, false, false], - [14, 1, false, false, false, false], - [14, 2, false, true, false, true], - [14, 3, false, true, false, true], - [14, 4, false, true, false, true], - [14, 5, false, true, false, true], - [14, 6, true, false, true, false], - [14, 7, true, false, true, false], - [14, 8, true, false, true, false], - [14, 9, true, false, true, false], - [14, 10, true, false, true, false], - [14, 11, false, false, true, true], - [14, 12, false, false, true, true], - [14, 13, false, false, true, true], - [14, 14, false, false, true, true], - [14, 15, false, false, false, false], - [14, 16, false, false, false, false], - [14, 17, false, false, false, false], - [14, 18, false, false, false, false], - [14, 19, false, false, false, false], - [14, 20, false, false, false, false], - [14, 21, false, false, false, false], - [15, 0, false, false, true, true], - [15, 1, true, false, true, false], - [15, 2, false, true, false, true], - [15, 3, false, false, true, true], - [15, 4, true, false, true, false], - [15, 5, false, false, false, false], - [15, 6, false, false, false, false], - [15, 7, false, false, false, false], - [15, 8, false, false, false, false], - [15, 9, false, false, false, false], - [15, 10, false, false, false, false], - [15, 11, false, false, false, false], - [15, 12, false, false, false, false], - [15, 13, false, false, false, false], - [15, 14, false, false, false, false], - [15, 15, false, false, true, true], - [15, 16, false, true, false, true], - [15, 17, false, false, false, false], - [15, 18, false, true, false, true], - [15, 19, false, false, false, false], - [15, 20, true, false, true, false], - [15, 21, false, true, false, true], - [16, 0, true, false, true, false], - [16, 1, true, false, true, false], - [16, 2, false, false, true, true], - [16, 3, true, false, true, false], - [16, 4, true, false, true, false], - [16, 5, false, false, false, false], - [16, 6, false, false, false, false], - [16, 7, false, false, false, false], - [16, 8, false, false, false, false], - [16, 9, false, false, false, false], - [16, 10, false, false, false, false], - [16, 11, false, false, false, false], - [16, 12, false, false, false, false], - [16, 13, false, false, false, false], - [16, 14, false, false, false, false], - [16, 15, true, false, true, false], - [16, 16, false, false, true, true], - [16, 17, false, false, false, false], - [16, 18, false, false, true, true], - [16, 19, false, false, false, false], - [16, 20, true, false, true, false], - [16, 21, false, true, false, true], - [17, 0, false, false, false, false], - [17, 1, false, false, false, false], - [17, 2, false, false, false, false], - [17, 3, false, false, false, false], - [17, 4, false, false, false, false], - [17, 5, false, false, false, false], - [17, 6, false, false, false, false], - [17, 7, false, false, false, false], - [17, 8, false, false, false, false], - [17, 9, false, false, false, false], - [17, 10, false, false, false, false], - [17, 11, false, false, false, false], - [17, 12, false, false, false, false], - [17, 13, false, false, false, false], - [17, 14, false, false, false, false], - [17, 15, false, false, false, false], - [17, 16, false, false, false, false], - [17, 17, false, false, false, false], - [17, 18, false, false, false, false], - [17, 19, false, false, false, false], - [17, 20, false, false, false, false], - [17, 21, false, false, false, false], - [18, 0, true, false, true, false], - [18, 1, true, false, true, false], - [18, 2, false, false, true, true], - [18, 3, true, false, true, false], - [18, 4, true, false, true, false], - [18, 5, false, false, false, false], - [18, 6, false, false, false, false], - [18, 7, false, false, false, false], - [18, 8, false, false, false, false], - [18, 9, false, false, false, false], - [18, 10, false, false, false, false], - [18, 11, false, false, false, false], - [18, 12, false, false, false, false], - [18, 13, false, false, false, false], - [18, 14, false, false, false, false], - [18, 15, true, false, true, false], - [18, 16, false, false, true, true], - [18, 17, false, false, false, false], - [18, 18, false, false, true, true], - [18, 19, false, false, false, false], - [18, 20, true, false, true, false], - [18, 21, false, true, false, true], - [19, 0, false, false, false, false], - [19, 1, false, false, false, false], - [19, 2, false, false, false, false], - [19, 3, false, false, false, false], - [19, 4, false, false, false, false], - [19, 5, false, false, false, false], - [19, 6, false, false, false, false], - [19, 7, false, false, false, false], - [19, 8, false, false, false, false], - [19, 9, false, false, false, false], - [19, 10, false, false, false, false], - [19, 11, false, false, false, false], - [19, 12, false, false, false, false], - [19, 13, false, false, false, false], - [19, 14, false, false, false, false], - [19, 15, false, false, false, false], - [19, 16, false, false, false, false], - [19, 17, false, false, false, false], - [19, 18, false, false, false, false], - [19, 19, false, false, false, false], - [19, 20, false, false, false, false], - [19, 21, false, false, false, false], - [20, 0, false, true, false, true], - [20, 1, false, true, false, true], - [20, 2, false, true, false, true], - [20, 3, false, true, false, true], - [20, 4, false, true, false, true], - [20, 5, false, false, false, false], - [20, 6, false, false, false, false], - [20, 7, false, false, false, false], - [20, 8, false, false, false, false], - [20, 9, false, false, false, false], - [20, 10, false, false, false, false], - [20, 11, false, false, false, false], - [20, 12, false, false, false, false], - [20, 13, false, false, false, false], - [20, 14, false, false, false, false], - [20, 15, false, true, false, true], - [20, 16, false, true, false, true], - [20, 17, false, false, false, false], - [20, 18, false, true, false, true], - [20, 19, false, false, false, false], - [20, 20, false, false, true, true], - [20, 21, false, true, false, true], - [21, 0, true, false, true, false], - [21, 1, true, false, true, false], - [21, 2, true, false, true, false], - [21, 3, true, false, true, false], - [21, 4, true, false, true, false], - [21, 5, false, false, false, false], - [21, 6, false, false, false, false], - [21, 7, false, false, false, false], - [21, 8, false, false, false, false], - [21, 9, false, false, false, false], - [21, 10, false, false, false, false], - [21, 11, false, false, false, false], - [21, 12, false, false, false, false], - [21, 13, false, false, false, false], - [21, 14, false, false, false, false], - [21, 15, true, false, true, false], - [21, 16, true, false, true, false], - [21, 17, false, false, false, false], - [21, 18, true, false, true, false], - [21, 19, false, false, false, false], - [21, 20, true, false, true, false], - [21, 21, false, false, true, true], - ]; + // Each row contains: xIndex, yIndex, (x < y), (x > y), (x <= y), (x >= y) + // where x = vals[xIndex], y = vals[yIndex] + // Table can be generated using a mature engine and the following code: + // for (var xIndex = 0; xIndex < vals.length; ++xIndex) { + // for (var yIndex = 0; yIndex < vals.length; ++yIndex) { + // var x = vals[xIndex]; + // var y = vals[yIndex]; + // console.log(`[${xIndex}, ${yIndex}, ${x < y}, ${x > y}, ${x <= y}, ${x >= y}]`); + // } + // } + const table = [ + [0, 0, false, false, true, true], + [0, 1, true, false, true, false], + [0, 2, true, false, true, false], + [0, 3, true, false, true, false], + [0, 4, false, false, true, true], + [0, 5, true, false, true, false], + [0, 6, false, true, false, true], + [0, 7, false, false, true, true], + [0, 8, true, false, true, false], + [0, 9, false, false, false, false], + [0, 10, false, false, false, false], + [0, 11, false, false, false, false], + [0, 12, false, false, false, false], + [0, 13, false, false, false, false], + [0, 14, false, false, false, false], + [0, 15, false, false, false, false], + [0, 16, false, false, false, false], + [0, 17, false, false, false, false], + [0, 18, false, false, false, false], + [0, 19, false, false, true, true], + [0, 20, false, true, false, true], + [0, 21, false, false, false, false], + [0, 22, false, true, false, true], + [0, 23, false, false, false, false], + [0, 24, true, false, true, false], + [0, 25, false, true, false, true], + [1, 0, false, true, false, true], + [1, 1, false, false, true, true], + [1, 2, false, true, false, true], + [1, 3, true, false, true, false], + [1, 4, false, true, false, true], + [1, 5, false, false, true, true], + [1, 6, false, true, false, true], + [1, 7, false, true, false, true], + [1, 8, false, false, true, true], + [1, 9, false, false, false, false], + [1, 10, false, false, false, false], + [1, 11, false, false, false, false], + [1, 12, false, false, false, false], + [1, 13, false, false, false, false], + [1, 14, false, false, false, false], + [1, 15, false, false, false, false], + [1, 16, false, false, false, false], + [1, 17, false, false, false, false], + [1, 18, false, false, false, false], + [1, 19, false, true, false, true], + [1, 20, false, true, false, true], + [1, 21, false, false, false, false], + [1, 22, false, true, false, true], + [1, 23, false, false, false, false], + [1, 24, true, false, true, false], + [1, 25, false, true, false, true], + [2, 0, false, true, false, true], + [2, 1, true, false, true, false], + [2, 2, false, false, true, true], + [2, 3, true, false, true, false], + [2, 4, false, true, false, true], + [2, 5, true, false, true, false], + [2, 6, false, true, false, true], + [2, 7, false, true, false, true], + [2, 8, true, false, true, false], + [2, 9, false, false, false, false], + [2, 10, false, false, false, false], + [2, 11, false, false, false, false], + [2, 12, false, false, false, false], + [2, 13, false, false, false, false], + [2, 14, false, false, false, false], + [2, 15, false, false, false, false], + [2, 16, false, false, false, false], + [2, 17, false, false, false, false], + [2, 18, false, false, false, false], + [2, 19, false, true, false, true], + [2, 20, false, true, false, true], + [2, 21, false, false, false, false], + [2, 22, false, true, false, true], + [2, 23, false, false, false, false], + [2, 24, true, false, true, false], + [2, 25, false, true, false, true], + [3, 0, false, true, false, true], + [3, 1, false, true, false, true], + [3, 2, false, true, false, true], + [3, 3, false, false, true, true], + [3, 4, false, true, false, true], + [3, 5, false, true, false, true], + [3, 6, false, true, false, true], + [3, 7, false, true, false, true], + [3, 8, false, true, false, true], + [3, 9, false, false, false, false], + [3, 10, false, false, false, false], + [3, 11, false, false, false, false], + [3, 12, false, false, false, false], + [3, 13, false, false, false, false], + [3, 14, false, false, false, false], + [3, 15, false, false, false, false], + [3, 16, false, false, false, false], + [3, 17, false, false, false, false], + [3, 18, false, false, false, false], + [3, 19, false, true, false, true], + [3, 20, false, true, false, true], + [3, 21, false, false, false, false], + [3, 22, false, true, false, true], + [3, 23, false, false, false, false], + [3, 24, true, false, true, false], + [3, 25, false, true, false, true], + [4, 0, false, false, true, true], + [4, 1, true, false, true, false], + [4, 2, true, false, true, false], + [4, 3, true, false, true, false], + [4, 4, false, false, true, true], + [4, 5, true, false, true, false], + [4, 6, false, true, false, true], + [4, 7, false, false, true, true], + [4, 8, true, false, true, false], + [4, 9, false, false, false, false], + [4, 10, false, false, false, false], + [4, 11, false, false, false, false], + [4, 12, false, false, false, false], + [4, 13, false, false, false, false], + [4, 14, false, false, false, false], + [4, 15, false, false, false, false], + [4, 16, false, false, false, false], + [4, 17, false, false, false, false], + [4, 18, false, false, false, false], + [4, 19, false, false, true, true], + [4, 20, false, true, false, true], + [4, 21, false, false, false, false], + [4, 22, false, true, false, true], + [4, 23, false, false, false, false], + [4, 24, true, false, true, false], + [4, 25, false, true, false, true], + [5, 0, false, true, false, true], + [5, 1, false, false, true, true], + [5, 2, false, true, false, true], + [5, 3, true, false, true, false], + [5, 4, false, true, false, true], + [5, 5, false, false, true, true], + [5, 6, false, true, false, true], + [5, 7, false, true, false, true], + [5, 8, false, false, true, true], + [5, 9, false, false, false, false], + [5, 10, false, false, false, false], + [5, 11, false, false, false, false], + [5, 12, false, false, false, false], + [5, 13, false, false, false, false], + [5, 14, false, false, false, false], + [5, 15, false, false, false, false], + [5, 16, false, false, false, false], + [5, 17, false, false, false, false], + [5, 18, false, false, false, false], + [5, 19, false, true, false, true], + [5, 20, false, true, false, true], + [5, 21, false, false, false, false], + [5, 22, false, true, false, true], + [5, 23, false, false, false, false], + [5, 24, true, false, true, false], + [5, 25, false, true, false, true], + [6, 0, true, false, true, false], + [6, 1, true, false, true, false], + [6, 2, true, false, true, false], + [6, 3, true, false, true, false], + [6, 4, true, false, true, false], + [6, 5, true, false, true, false], + [6, 6, false, false, true, true], + [6, 7, true, false, true, false], + [6, 8, true, false, true, false], + [6, 9, true, false, true, false], + [6, 10, true, false, true, false], + [6, 11, true, false, true, false], + [6, 12, true, false, true, false], + [6, 13, true, false, true, false], + [6, 14, true, false, true, false], + [6, 15, true, false, true, false], + [6, 16, true, false, true, false], + [6, 17, true, false, true, false], + [6, 18, true, false, true, false], + [6, 19, true, false, true, false], + [6, 20, false, false, true, true], + [6, 21, false, false, false, false], + [6, 22, false, false, true, true], + [6, 23, false, false, false, false], + [6, 24, true, false, true, false], + [6, 25, false, true, false, true], + [7, 0, false, false, true, true], + [7, 1, true, false, true, false], + [7, 2, true, false, true, false], + [7, 3, true, false, true, false], + [7, 4, false, false, true, true], + [7, 5, true, false, true, false], + [7, 6, false, true, false, true], + [7, 7, false, false, true, true], + [7, 8, true, false, true, false], + [7, 9, true, false, true, false], + [7, 10, true, false, true, false], + [7, 11, true, false, true, false], + [7, 12, true, false, true, false], + [7, 13, true, false, true, false], + [7, 14, true, false, true, false], + [7, 15, true, false, true, false], + [7, 16, true, false, true, false], + [7, 17, true, false, true, false], + [7, 18, true, false, true, false], + [7, 19, false, false, true, true], + [7, 20, false, true, false, true], + [7, 21, false, false, false, false], + [7, 22, false, true, false, true], + [7, 23, false, false, false, false], + [7, 24, true, false, true, false], + [7, 25, false, true, false, true], + [8, 0, false, true, false, true], + [8, 1, false, false, true, true], + [8, 2, false, true, false, true], + [8, 3, true, false, true, false], + [8, 4, false, true, false, true], + [8, 5, false, false, true, true], + [8, 6, false, true, false, true], + [8, 7, false, true, false, true], + [8, 8, false, false, true, true], + [8, 9, false, true, false, true], + [8, 10, true, false, true, false], + [8, 11, true, false, true, false], + [8, 12, true, false, true, false], + [8, 13, true, false, true, false], + [8, 14, true, false, true, false], + [8, 15, true, false, true, false], + [8, 16, true, false, true, false], + [8, 17, true, false, true, false], + [8, 18, true, false, true, false], + [8, 19, false, true, false, true], + [8, 20, false, true, false, true], + [8, 21, false, false, false, false], + [8, 22, false, true, false, true], + [8, 23, false, false, false, false], + [8, 24, true, false, true, false], + [8, 25, false, true, false, true], + [9, 0, false, false, false, false], + [9, 1, false, false, false, false], + [9, 2, false, false, false, false], + [9, 3, false, false, false, false], + [9, 4, false, false, false, false], + [9, 5, false, false, false, false], + [9, 6, false, true, false, true], + [9, 7, false, true, false, true], + [9, 8, true, false, true, false], + [9, 9, false, false, true, true], + [9, 10, true, false, true, false], + [9, 11, true, false, true, false], + [9, 12, true, false, true, false], + [9, 13, true, false, true, false], + [9, 14, true, false, true, false], + [9, 15, true, false, true, false], + [9, 16, true, false, true, false], + [9, 17, true, false, true, false], + [9, 18, true, false, true, false], + [9, 19, false, false, false, false], + [9, 20, false, false, false, false], + [9, 21, false, false, false, false], + [9, 22, false, false, false, false], + [9, 23, false, false, false, false], + [9, 24, false, false, false, false], + [9, 25, false, false, false, false], + [10, 0, false, false, false, false], + [10, 1, false, false, false, false], + [10, 2, false, false, false, false], + [10, 3, false, false, false, false], + [10, 4, false, false, false, false], + [10, 5, false, false, false, false], + [10, 6, false, true, false, true], + [10, 7, false, true, false, true], + [10, 8, false, true, false, true], + [10, 9, false, true, false, true], + [10, 10, false, false, true, true], + [10, 11, true, false, true, false], + [10, 12, true, false, true, false], + [10, 13, true, false, true, false], + [10, 14, false, true, false, true], + [10, 15, false, true, false, true], + [10, 16, false, true, false, true], + [10, 17, false, true, false, true], + [10, 18, false, true, false, true], + [10, 19, false, false, false, false], + [10, 20, false, false, false, false], + [10, 21, false, false, false, false], + [10, 22, false, false, false, false], + [10, 23, false, false, false, false], + [10, 24, false, false, false, false], + [10, 25, false, false, false, false], + [11, 0, false, false, false, false], + [11, 1, false, false, false, false], + [11, 2, false, false, false, false], + [11, 3, false, false, false, false], + [11, 4, false, false, false, false], + [11, 5, false, false, false, false], + [11, 6, false, true, false, true], + [11, 7, false, true, false, true], + [11, 8, false, true, false, true], + [11, 9, false, true, false, true], + [11, 10, false, true, false, true], + [11, 11, false, false, true, true], + [11, 12, true, false, true, false], + [11, 13, true, false, true, false], + [11, 14, false, true, false, true], + [11, 15, false, true, false, true], + [11, 16, false, true, false, true], + [11, 17, false, true, false, true], + [11, 18, false, true, false, true], + [11, 19, false, false, false, false], + [11, 20, false, false, false, false], + [11, 21, false, false, false, false], + [11, 22, false, false, false, false], + [11, 23, false, false, false, false], + [11, 24, false, false, false, false], + [11, 25, false, false, false, false], + [12, 0, false, false, false, false], + [12, 1, false, false, false, false], + [12, 2, false, false, false, false], + [12, 3, false, false, false, false], + [12, 4, false, false, false, false], + [12, 5, false, false, false, false], + [12, 6, false, true, false, true], + [12, 7, false, true, false, true], + [12, 8, false, true, false, true], + [12, 9, false, true, false, true], + [12, 10, false, true, false, true], + [12, 11, false, true, false, true], + [12, 12, false, false, true, true], + [12, 13, false, true, false, true], + [12, 14, false, true, false, true], + [12, 15, false, true, false, true], + [12, 16, false, true, false, true], + [12, 17, false, true, false, true], + [12, 18, false, true, false, true], + [12, 19, false, false, false, false], + [12, 20, false, false, false, false], + [12, 21, false, false, false, false], + [12, 22, false, false, false, false], + [12, 23, false, false, false, false], + [12, 24, false, false, false, false], + [12, 25, false, false, false, false], + [13, 0, false, false, false, false], + [13, 1, false, false, false, false], + [13, 2, false, false, false, false], + [13, 3, false, false, false, false], + [13, 4, false, false, false, false], + [13, 5, false, false, false, false], + [13, 6, false, true, false, true], + [13, 7, false, true, false, true], + [13, 8, false, true, false, true], + [13, 9, false, true, false, true], + [13, 10, false, true, false, true], + [13, 11, false, true, false, true], + [13, 12, true, false, true, false], + [13, 13, false, false, true, true], + [13, 14, false, true, false, true], + [13, 15, false, true, false, true], + [13, 16, false, true, false, true], + [13, 17, false, true, false, true], + [13, 18, false, true, false, true], + [13, 19, false, false, false, false], + [13, 20, false, false, false, false], + [13, 21, false, false, false, false], + [13, 22, false, false, false, false], + [13, 23, false, false, false, false], + [13, 24, false, false, false, false], + [13, 25, false, false, false, false], + [14, 0, false, false, false, false], + [14, 1, false, false, false, false], + [14, 2, false, false, false, false], + [14, 3, false, false, false, false], + [14, 4, false, false, false, false], + [14, 5, false, false, false, false], + [14, 6, false, true, false, true], + [14, 7, false, true, false, true], + [14, 8, false, true, false, true], + [14, 9, false, true, false, true], + [14, 10, true, false, true, false], + [14, 11, true, false, true, false], + [14, 12, true, false, true, false], + [14, 13, true, false, true, false], + [14, 14, false, false, true, true], + [14, 15, false, true, false, true], + [14, 16, false, true, false, true], + [14, 17, false, true, false, true], + [14, 18, false, true, false, true], + [14, 19, false, false, false, false], + [14, 20, false, false, false, false], + [14, 21, false, false, false, false], + [14, 22, false, false, false, false], + [14, 23, false, false, false, false], + [14, 24, false, false, false, false], + [14, 25, false, false, false, false], + [15, 0, false, false, false, false], + [15, 1, false, false, false, false], + [15, 2, false, false, false, false], + [15, 3, false, false, false, false], + [15, 4, false, false, false, false], + [15, 5, false, false, false, false], + [15, 6, false, true, false, true], + [15, 7, false, true, false, true], + [15, 8, false, true, false, true], + [15, 9, false, true, false, true], + [15, 10, true, false, true, false], + [15, 11, true, false, true, false], + [15, 12, true, false, true, false], + [15, 13, true, false, true, false], + [15, 14, true, false, true, false], + [15, 15, false, false, true, true], + [15, 16, false, false, true, true], + [15, 17, false, false, true, true], + [15, 18, false, false, true, true], + [15, 19, false, false, false, false], + [15, 20, false, false, false, false], + [15, 21, false, false, false, false], + [15, 22, false, false, false, false], + [15, 23, false, false, false, false], + [15, 24, false, false, false, false], + [15, 25, false, false, false, false], + [16, 0, false, false, false, false], + [16, 1, false, false, false, false], + [16, 2, false, false, false, false], + [16, 3, false, false, false, false], + [16, 4, false, false, false, false], + [16, 5, false, false, false, false], + [16, 6, false, true, false, true], + [16, 7, false, true, false, true], + [16, 8, false, true, false, true], + [16, 9, false, true, false, true], + [16, 10, true, false, true, false], + [16, 11, true, false, true, false], + [16, 12, true, false, true, false], + [16, 13, true, false, true, false], + [16, 14, true, false, true, false], + [16, 15, false, false, true, true], + [16, 16, false, false, true, true], + [16, 17, false, false, true, true], + [16, 18, false, false, true, true], + [16, 19, false, false, false, false], + [16, 20, false, false, false, false], + [16, 21, false, false, false, false], + [16, 22, false, false, false, false], + [16, 23, false, false, false, false], + [16, 24, false, false, false, false], + [16, 25, false, false, false, false], + [17, 0, false, false, false, false], + [17, 1, false, false, false, false], + [17, 2, false, false, false, false], + [17, 3, false, false, false, false], + [17, 4, false, false, false, false], + [17, 5, false, false, false, false], + [17, 6, false, true, false, true], + [17, 7, false, true, false, true], + [17, 8, false, true, false, true], + [17, 9, false, true, false, true], + [17, 10, true, false, true, false], + [17, 11, true, false, true, false], + [17, 12, true, false, true, false], + [17, 13, true, false, true, false], + [17, 14, true, false, true, false], + [17, 15, false, false, true, true], + [17, 16, false, false, true, true], + [17, 17, false, false, true, true], + [17, 18, false, false, true, true], + [17, 19, false, false, false, false], + [17, 20, false, false, false, false], + [17, 21, false, false, false, false], + [17, 22, false, false, false, false], + [17, 23, false, false, false, false], + [17, 24, false, false, false, false], + [17, 25, false, false, false, false], + [18, 0, false, false, false, false], + [18, 1, false, false, false, false], + [18, 2, false, false, false, false], + [18, 3, false, false, false, false], + [18, 4, false, false, false, false], + [18, 5, false, false, false, false], + [18, 6, false, true, false, true], + [18, 7, false, true, false, true], + [18, 8, false, true, false, true], + [18, 9, false, true, false, true], + [18, 10, true, false, true, false], + [18, 11, true, false, true, false], + [18, 12, true, false, true, false], + [18, 13, true, false, true, false], + [18, 14, true, false, true, false], + [18, 15, false, false, true, true], + [18, 16, false, false, true, true], + [18, 17, false, false, true, true], + [18, 18, false, false, true, true], + [18, 19, false, false, false, false], + [18, 20, false, false, false, false], + [18, 21, false, false, false, false], + [18, 22, false, false, false, false], + [18, 23, false, false, false, false], + [18, 24, false, false, false, false], + [18, 25, false, false, false, false], + [19, 0, false, false, true, true], + [19, 1, true, false, true, false], + [19, 2, true, false, true, false], + [19, 3, true, false, true, false], + [19, 4, false, false, true, true], + [19, 5, true, false, true, false], + [19, 6, false, true, false, true], + [19, 7, false, false, true, true], + [19, 8, true, false, true, false], + [19, 9, false, false, false, false], + [19, 10, false, false, false, false], + [19, 11, false, false, false, false], + [19, 12, false, false, false, false], + [19, 13, false, false, false, false], + [19, 14, false, false, false, false], + [19, 15, false, false, false, false], + [19, 16, false, false, false, false], + [19, 17, false, false, false, false], + [19, 18, false, false, false, false], + [19, 19, false, false, true, true], + [19, 20, false, true, false, true], + [19, 21, false, false, false, false], + [19, 22, false, true, false, true], + [19, 23, false, false, false, false], + [19, 24, true, false, true, false], + [19, 25, false, true, false, true], + [20, 0, true, false, true, false], + [20, 1, true, false, true, false], + [20, 2, true, false, true, false], + [20, 3, true, false, true, false], + [20, 4, true, false, true, false], + [20, 5, true, false, true, false], + [20, 6, false, false, true, true], + [20, 7, true, false, true, false], + [20, 8, true, false, true, false], + [20, 9, false, false, false, false], + [20, 10, false, false, false, false], + [20, 11, false, false, false, false], + [20, 12, false, false, false, false], + [20, 13, false, false, false, false], + [20, 14, false, false, false, false], + [20, 15, false, false, false, false], + [20, 16, false, false, false, false], + [20, 17, false, false, false, false], + [20, 18, false, false, false, false], + [20, 19, true, false, true, false], + [20, 20, false, false, true, true], + [20, 21, false, false, false, false], + [20, 22, false, false, true, true], + [20, 23, false, false, false, false], + [20, 24, true, false, true, false], + [20, 25, false, true, false, true], + [21, 0, false, false, false, false], + [21, 1, false, false, false, false], + [21, 2, false, false, false, false], + [21, 3, false, false, false, false], + [21, 4, false, false, false, false], + [21, 5, false, false, false, false], + [21, 6, false, false, false, false], + [21, 7, false, false, false, false], + [21, 8, false, false, false, false], + [21, 9, false, false, false, false], + [21, 10, false, false, false, false], + [21, 11, false, false, false, false], + [21, 12, false, false, false, false], + [21, 13, false, false, false, false], + [21, 14, false, false, false, false], + [21, 15, false, false, false, false], + [21, 16, false, false, false, false], + [21, 17, false, false, false, false], + [21, 18, false, false, false, false], + [21, 19, false, false, false, false], + [21, 20, false, false, false, false], + [21, 21, false, false, false, false], + [21, 22, false, false, false, false], + [21, 23, false, false, false, false], + [21, 24, false, false, false, false], + [21, 25, false, false, false, false], + [22, 0, true, false, true, false], + [22, 1, true, false, true, false], + [22, 2, true, false, true, false], + [22, 3, true, false, true, false], + [22, 4, true, false, true, false], + [22, 5, true, false, true, false], + [22, 6, false, false, true, true], + [22, 7, true, false, true, false], + [22, 8, true, false, true, false], + [22, 9, false, false, false, false], + [22, 10, false, false, false, false], + [22, 11, false, false, false, false], + [22, 12, false, false, false, false], + [22, 13, false, false, false, false], + [22, 14, false, false, false, false], + [22, 15, false, false, false, false], + [22, 16, false, false, false, false], + [22, 17, false, false, false, false], + [22, 18, false, false, false, false], + [22, 19, true, false, true, false], + [22, 20, false, false, true, true], + [22, 21, false, false, false, false], + [22, 22, false, false, true, true], + [22, 23, false, false, false, false], + [22, 24, true, false, true, false], + [22, 25, false, true, false, true], + [23, 0, false, false, false, false], + [23, 1, false, false, false, false], + [23, 2, false, false, false, false], + [23, 3, false, false, false, false], + [23, 4, false, false, false, false], + [23, 5, false, false, false, false], + [23, 6, false, false, false, false], + [23, 7, false, false, false, false], + [23, 8, false, false, false, false], + [23, 9, false, false, false, false], + [23, 10, false, false, false, false], + [23, 11, false, false, false, false], + [23, 12, false, false, false, false], + [23, 13, false, false, false, false], + [23, 14, false, false, false, false], + [23, 15, false, false, false, false], + [23, 16, false, false, false, false], + [23, 17, false, false, false, false], + [23, 18, false, false, false, false], + [23, 19, false, false, false, false], + [23, 20, false, false, false, false], + [23, 21, false, false, false, false], + [23, 22, false, false, false, false], + [23, 23, false, false, false, false], + [23, 24, false, false, false, false], + [23, 25, false, false, false, false], + [24, 0, false, true, false, true], + [24, 1, false, true, false, true], + [24, 2, false, true, false, true], + [24, 3, false, true, false, true], + [24, 4, false, true, false, true], + [24, 5, false, true, false, true], + [24, 6, false, true, false, true], + [24, 7, false, true, false, true], + [24, 8, false, true, false, true], + [24, 9, false, false, false, false], + [24, 10, false, false, false, false], + [24, 11, false, false, false, false], + [24, 12, false, false, false, false], + [24, 13, false, false, false, false], + [24, 14, false, false, false, false], + [24, 15, false, false, false, false], + [24, 16, false, false, false, false], + [24, 17, false, false, false, false], + [24, 18, false, false, false, false], + [24, 19, false, true, false, true], + [24, 20, false, true, false, true], + [24, 21, false, false, false, false], + [24, 22, false, true, false, true], + [24, 23, false, false, false, false], + [24, 24, false, false, true, true], + [24, 25, false, true, false, true], + [25, 0, true, false, true, false], + [25, 1, true, false, true, false], + [25, 2, true, false, true, false], + [25, 3, true, false, true, false], + [25, 4, true, false, true, false], + [25, 5, true, false, true, false], + [25, 6, true, false, true, false], + [25, 7, true, false, true, false], + [25, 8, true, false, true, false], + [25, 9, false, false, false, false], + [25, 10, false, false, false, false], + [25, 11, false, false, false, false], + [25, 12, false, false, false, false], + [25, 13, false, false, false, false], + [25, 14, false, false, false, false], + [25, 15, false, false, false, false], + [25, 16, false, false, false, false], + [25, 17, false, false, false, false], + [25, 18, false, false, false, false], + [25, 19, true, false, true, false], + [25, 20, true, false, true, false], + [25, 21, false, false, false, false], + [25, 22, true, false, true, false], + [25, 23, false, false, false, false], + [25, 24, true, false, true, false], + [25, 25, false, false, true, true], + ]; - for (let test of table) { - let x = vals[test[0]]; - let y = vals[test[1]]; + for (let test of table) { + let x = vals[test[0]]; + let y = vals[test[1]]; - assert(x < y === test[2]); - assert(x > y === test[3]); - assert(x <= y === test[4]); - assert(x >= y === test[5]); - } + assert(x < y === test[2]); + assert(x > y === test[3]); + assert(x <= y === test[4]); + assert(x >= y === test[5]); + } - console.log("PASS"); + console.log("PASS"); } catch (e) { - console.log("FAIL: " + e); + console.log("FAIL: " + e); } diff --git a/Libraries/LibJS/Tests/object-basic.js b/Libraries/LibJS/Tests/object-basic.js index d8dfcce02f..04580afa0c 100644 --- a/Libraries/LibJS/Tests/object-basic.js +++ b/Libraries/LibJS/Tests/object-basic.js @@ -15,6 +15,7 @@ try { duplicate: "world" }; assert(o[1] === 23); + assert(o[1n] === 23); assert(o["1"] === 23); assert(o.foo === "bar"); assert(o["foo"] === "bar"); @@ -30,6 +31,9 @@ try { o[10] = "123"; assert(o[10] === "123"); assert(o["10"] === "123"); + o[10n] = "123"; + assert(o[10] === "123"); + assert(o["10"] === "123"); o[-1] = "hello friends"; assert(o[-1] === "hello friends"); assert(o["-1"] === "hello friends"); diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index e12747df0b..ccc445dc98 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -40,6 +40,7 @@ namespace JS { __ENUMERATE_JS_TOKEN(AsteriskEquals) \ __ENUMERATE_JS_TOKEN(Async) \ __ENUMERATE_JS_TOKEN(Await) \ + __ENUMERATE_JS_TOKEN(BigIntLiteral) \ __ENUMERATE_JS_TOKEN(BoolLiteral) \ __ENUMERATE_JS_TOKEN(BracketClose) \ __ENUMERATE_JS_TOKEN(BracketOpen) \ |