summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-04-05 13:40:00 +0100
committerAndreas Kling <kling@serenityos.org>2020-04-05 15:32:06 +0200
commit0403845d3edce9caf6823e0579074f57e9a4b9b9 (patch)
treef545e5cc2f4be20bd90d696174090e333077512c /Libraries
parenteafd3dbaf88461ba7fb99ce8c5c6e7a295bed9b4 (diff)
downloadserenity-0403845d3edce9caf6823e0579074f57e9a4b9b9.zip
LibJS: Implement exponentiation (** operator)
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/AST.cpp5
-rw-r--r--Libraries/LibJS/AST.h1
-rw-r--r--Libraries/LibJS/Parser.cpp4
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp6
-rw-r--r--Libraries/LibJS/Runtime/Value.h1
-rw-r--r--Libraries/LibJS/Tests/exponentiation-basic.js30
-rw-r--r--Libraries/LibJS/Tests/modulo-basic.js2
7 files changed, 48 insertions, 1 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index 5a7f8cc152..8bd75e4a90 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -283,6 +283,8 @@ Value BinaryExpression::execute(Interpreter& interpreter) const
return div(lhs_result, rhs_result);
case BinaryOp::Modulo:
return mod(lhs_result, rhs_result);
+ case BinaryOp::Exponentiation:
+ return exp(lhs_result, rhs_result);
case BinaryOp::TypedEquals:
return typed_eq(lhs_result, rhs_result);
case BinaryOp::TypedInequals:
@@ -421,6 +423,9 @@ void BinaryExpression::dump(int indent) const
case BinaryOp::Modulo:
op_string = "%";
break;
+ case BinaryOp::Exponentiation:
+ op_string = "**";
+ break;
case BinaryOp::TypedEquals:
op_string = "===";
break;
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index af6b13bced..3c0d761127 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -314,6 +314,7 @@ enum class BinaryOp {
Multiplication,
Division,
Modulo,
+ Exponentiation,
TypedEquals,
TypedInequals,
AbstractEquals,
diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp
index 780b953121..3a9bfb2900 100644
--- a/Libraries/LibJS/Parser.cpp
+++ b/Libraries/LibJS/Parser.cpp
@@ -470,6 +470,9 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
case TokenType::Percent:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity));
+ case TokenType::DoubleAsterisk:
+ consume();
+ return create_ast_node<BinaryExpression>(BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::GreaterThan:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity));
@@ -905,6 +908,7 @@ bool Parser::match_secondary_expression() const
|| type == TokenType::Slash
|| type == TokenType::SlashEquals
|| type == TokenType::Percent
+ || type == TokenType::DoubleAsterisk
|| type == TokenType::Equals
|| type == TokenType::EqualsEqualsEquals
|| type == TokenType::ExclamationMarkEqualsEquals
diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp
index 13687cb5b3..ea0594245f 100644
--- a/Libraries/LibJS/Runtime/Value.cpp
+++ b/Libraries/LibJS/Runtime/Value.cpp
@@ -35,6 +35,7 @@
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/StringObject.h>
#include <LibJS/Runtime/Value.h>
+#include <math.h>
namespace JS {
@@ -268,6 +269,11 @@ Value mod(Value lhs, Value rhs)
return Value(index - trunc * period);
}
+Value exp(Value lhs, Value rhs)
+{
+ return Value(pow(lhs.to_number().as_double(), rhs.to_number().as_double()));
+}
+
Value typed_eq(Value lhs, Value rhs)
{
if (rhs.type() != lhs.type())
diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h
index df0e742ab9..b6d30c80f1 100644
--- a/Libraries/LibJS/Runtime/Value.h
+++ b/Libraries/LibJS/Runtime/Value.h
@@ -196,6 +196,7 @@ Value sub(Value lhs, Value rhs);
Value mul(Value lhs, Value rhs);
Value div(Value lhs, Value rhs);
Value mod(Value lhs, Value rhs);
+Value exp(Value lhs, Value rhs);
Value eq(Value lhs, Value rhs);
Value typed_eq(Value lhs, Value rhs);
Value instance_of(Value lhs, Value rhs);
diff --git a/Libraries/LibJS/Tests/exponentiation-basic.js b/Libraries/LibJS/Tests/exponentiation-basic.js
new file mode 100644
index 0000000000..995fd08117
--- /dev/null
+++ b/Libraries/LibJS/Tests/exponentiation-basic.js
@@ -0,0 +1,30 @@
+function assert(x) { if (!x) throw 1; }
+
+try {
+ assert(2 ** 0 === 1);
+ assert(2 ** 1 === 2);
+ assert(2 ** 2 === 4);
+ assert(2 ** 3 === 8);
+ assert(2 ** -3 === 0.125);
+ assert(3 ** 2 === 9);
+ assert(0 ** 0 === 1);
+ assert(2 ** 3 ** 2 === 512);
+ assert(2 ** (3 ** 2) === 512);
+ assert((2 ** 3) ** 2 === 64);
+ assert("2" ** "3" === 8);
+ assert("" ** [] === 1);
+ assert([] ** null === 1);
+ assert(null ** null === 1);
+ assert(undefined ** null === 1);
+ assert(isNaN(NaN ** 2));
+ assert(isNaN(2 ** NaN));
+ assert(isNaN(undefined ** 2));
+ assert(isNaN(2 ** undefined));
+ assert(isNaN(null ** undefined));
+ assert(isNaN(2 ** "foo"));
+ assert(isNaN("foo" ** 2));
+
+ console.log("PASS");
+} catch (e) {
+ console.log("FAIL: " + e);
+}
diff --git a/Libraries/LibJS/Tests/modulo-basic.js b/Libraries/LibJS/Tests/modulo-basic.js
index 4f35c2b3ea..e5b74d60e2 100644
--- a/Libraries/LibJS/Tests/modulo-basic.js
+++ b/Libraries/LibJS/Tests/modulo-basic.js
@@ -3,7 +3,7 @@ try {
assert(10.5 % 2.5 === 0.5);
assert(-0.99 % 0.99 === -0);
- // Examples form MDN:
+ // Examples from MDN:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
assert(12 % 5 === 2);
assert(-1 % 2 === -1);