Browse Source

Implemented exponentiation expressions. Closes #381.

Dmitry Panov 3 years ago
parent
commit
ff76422be7
8 changed files with 80 additions and 39 deletions
  1. 5 3
      builtin_math.go
  2. 7 0
      compiler_expr.go
  3. 45 32
      parser/expression.go
  4. 6 1
      parser/lexer.go
  5. 3 0
      parser/parser_test.go
  6. 0 3
      tc39_test.go
  7. 4 0
      token/token_const.go
  8. 10 0
      vm.go

+ 5 - 3
builtin_math.go

@@ -181,9 +181,7 @@ NaNLoop:
 	return _NaN
 }
 
-func (r *Runtime) math_pow(call FunctionCall) Value {
-	x := call.Argument(0)
-	y := call.Argument(1)
+func pow(x, y Value) Value {
 	if x, ok := x.(valueInt); ok {
 		if y, ok := y.(valueInt); ok && y >= 0 && y < 64 {
 			if y == 0 {
@@ -209,6 +207,10 @@ func (r *Runtime) math_pow(call FunctionCall) Value {
 	return floatToValue(math.Pow(xf, yf))
 }
 
+func (r *Runtime) math_pow(call FunctionCall) Value {
+	return pow(call.Argument(0), call.Argument(1))
+}
+
 func (r *Runtime) math_random(call FunctionCall) Value {
 	return floatToValue(r.rand())
 }

+ 7 - 0
compiler_expr.go

@@ -781,6 +781,11 @@ func (e *compiledAssignExpr) emitGetter(putOnStack bool) {
 			e.right.emitGetter(true)
 			e.c.emit(mul)
 		}, false, putOnStack)
+	case token.EXPONENT:
+		e.left.emitUnary(nil, func() {
+			e.right.emitGetter(true)
+			e.c.emit(exp)
+		}, false, putOnStack)
 	case token.SLASH:
 		e.left.emitUnary(nil, func() {
 			e.right.emitGetter(true)
@@ -1707,6 +1712,8 @@ func (e *compiledBinaryExpr) emitGetter(putOnStack bool) {
 		e.c.emit(sub)
 	case token.MULTIPLY:
 		e.c.emit(mul)
+	case token.EXPONENT:
+		e.c.emit(exp)
 	case token.SLASH:
 		e.c.emit(div)
 	case token.REMAINDER:

+ 45 - 32
parser/expression.go

@@ -757,9 +757,30 @@ func (self *_parser) parseUnaryExpression() ast.Expression {
 	return self.parsePostfixExpression()
 }
 
+func isUpdateExpression(expr ast.Expression) bool {
+	if ux, ok := expr.(*ast.UnaryExpression); ok {
+		return ux.Operator == token.INCREMENT || ux.Operator == token.DECREMENT
+	}
+	return true
+}
+
+func (self *_parser) parseExponentiationExpression() ast.Expression {
+	left := self.parseUnaryExpression()
+
+	for self.token == token.EXPONENT && isUpdateExpression(left) {
+		self.next()
+		left = &ast.BinaryExpression{
+			Operator: token.EXPONENT,
+			Left:     left,
+			Right:    self.parseExponentiationExpression(),
+		}
+	}
+
+	return left
+}
+
 func (self *_parser) parseMultiplicativeExpression() ast.Expression {
-	next := self.parseUnaryExpression
-	left := next()
+	left := self.parseExponentiationExpression()
 
 	for self.token == token.MULTIPLY || self.token == token.SLASH ||
 		self.token == token.REMAINDER {
@@ -768,7 +789,7 @@ func (self *_parser) parseMultiplicativeExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseExponentiationExpression(),
 		}
 	}
 
@@ -776,8 +797,7 @@ func (self *_parser) parseMultiplicativeExpression() ast.Expression {
 }
 
 func (self *_parser) parseAdditiveExpression() ast.Expression {
-	next := self.parseMultiplicativeExpression
-	left := next()
+	left := self.parseMultiplicativeExpression()
 
 	for self.token == token.PLUS || self.token == token.MINUS {
 		tkn := self.token
@@ -785,7 +805,7 @@ func (self *_parser) parseAdditiveExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseMultiplicativeExpression(),
 		}
 	}
 
@@ -793,8 +813,7 @@ func (self *_parser) parseAdditiveExpression() ast.Expression {
 }
 
 func (self *_parser) parseShiftExpression() ast.Expression {
-	next := self.parseAdditiveExpression
-	left := next()
+	left := self.parseAdditiveExpression()
 
 	for self.token == token.SHIFT_LEFT || self.token == token.SHIFT_RIGHT ||
 		self.token == token.UNSIGNED_SHIFT_RIGHT {
@@ -803,7 +822,7 @@ func (self *_parser) parseShiftExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseAdditiveExpression(),
 		}
 	}
 
@@ -811,8 +830,7 @@ func (self *_parser) parseShiftExpression() ast.Expression {
 }
 
 func (self *_parser) parseRelationalExpression() ast.Expression {
-	next := self.parseShiftExpression
-	left := next()
+	left := self.parseShiftExpression()
 
 	allowIn := self.scope.allowIn
 	self.scope.allowIn = true
@@ -855,8 +873,7 @@ func (self *_parser) parseRelationalExpression() ast.Expression {
 }
 
 func (self *_parser) parseEqualityExpression() ast.Expression {
-	next := self.parseRelationalExpression
-	left := next()
+	left := self.parseRelationalExpression()
 
 	for self.token == token.EQUAL || self.token == token.NOT_EQUAL ||
 		self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
@@ -865,7 +882,7 @@ func (self *_parser) parseEqualityExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator:   tkn,
 			Left:       left,
-			Right:      next(),
+			Right:      self.parseRelationalExpression(),
 			Comparison: true,
 		}
 	}
@@ -874,8 +891,7 @@ func (self *_parser) parseEqualityExpression() ast.Expression {
 }
 
 func (self *_parser) parseBitwiseAndExpression() ast.Expression {
-	next := self.parseEqualityExpression
-	left := next()
+	left := self.parseEqualityExpression()
 
 	for self.token == token.AND {
 		tkn := self.token
@@ -883,7 +899,7 @@ func (self *_parser) parseBitwiseAndExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseEqualityExpression(),
 		}
 	}
 
@@ -891,8 +907,7 @@ func (self *_parser) parseBitwiseAndExpression() ast.Expression {
 }
 
 func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
-	next := self.parseBitwiseAndExpression
-	left := next()
+	left := self.parseBitwiseAndExpression()
 
 	for self.token == token.EXCLUSIVE_OR {
 		tkn := self.token
@@ -900,7 +915,7 @@ func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseBitwiseAndExpression(),
 		}
 	}
 
@@ -908,8 +923,7 @@ func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
 }
 
 func (self *_parser) parseBitwiseOrExpression() ast.Expression {
-	next := self.parseBitwiseExclusiveOrExpression
-	left := next()
+	left := self.parseBitwiseExclusiveOrExpression()
 
 	for self.token == token.OR {
 		tkn := self.token
@@ -917,7 +931,7 @@ func (self *_parser) parseBitwiseOrExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseBitwiseExclusiveOrExpression(),
 		}
 	}
 
@@ -925,8 +939,7 @@ func (self *_parser) parseBitwiseOrExpression() ast.Expression {
 }
 
 func (self *_parser) parseLogicalAndExpression() ast.Expression {
-	next := self.parseBitwiseOrExpression
-	left := next()
+	left := self.parseBitwiseOrExpression()
 
 	for self.token == token.LOGICAL_AND {
 		tkn := self.token
@@ -934,7 +947,7 @@ func (self *_parser) parseLogicalAndExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseBitwiseOrExpression(),
 		}
 	}
 
@@ -942,8 +955,7 @@ func (self *_parser) parseLogicalAndExpression() ast.Expression {
 }
 
 func (self *_parser) parseLogicalOrExpression() ast.Expression {
-	next := self.parseLogicalAndExpression
-	left := next()
+	left := self.parseLogicalAndExpression()
 
 	for self.token == token.LOGICAL_OR {
 		tkn := self.token
@@ -951,7 +963,7 @@ func (self *_parser) parseLogicalOrExpression() ast.Expression {
 		left = &ast.BinaryExpression{
 			Operator: tkn,
 			Left:     left,
-			Right:    next(),
+			Right:    self.parseLogicalAndExpression(),
 		}
 	}
 
@@ -996,6 +1008,8 @@ func (self *_parser) parseAssignmentExpression() ast.Expression {
 		operator = token.MINUS
 	case token.MULTIPLY_ASSIGN:
 		operator = token.MULTIPLY
+	case token.EXPONENT_ASSIGN:
+		operator = token.EXPONENT
 	case token.QUOTIENT_ASSIGN:
 		operator = token.SLASH
 	case token.REMAINDER_ASSIGN:
@@ -1080,8 +1094,7 @@ func (self *_parser) parseExpression() ast.Expression {
 	if self.token == token.LET {
 		self.token = token.IDENTIFIER
 	}
-	next := self.parseAssignmentExpression
-	left := next()
+	left := self.parseAssignmentExpression()
 
 	if self.token == token.COMMA {
 		sequence := []ast.Expression{left}
@@ -1090,7 +1103,7 @@ func (self *_parser) parseExpression() ast.Expression {
 				break
 			}
 			self.next()
-			sequence = append(sequence, next())
+			sequence = append(sequence, self.parseAssignmentExpression())
 		}
 		return &ast.SequenceExpression{
 			Sequence: sequence,

+ 6 - 1
parser/lexer.go

@@ -356,7 +356,12 @@ func (self *_parser) scan() (tkn token.Token, literal string, parsedLiteral unis
 					insertSemicolon = true
 				}
 			case '*':
-				tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN)
+				if self.chr == '*' {
+					self.read()
+					tkn = self.switch2(token.EXPONENT, token.EXPONENT_ASSIGN)
+				} else {
+					tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN)
+				}
 			case '/':
 				if self.chr == '/' {
 					self.skipSingleLineComment()

+ 3 - 0
parser/parser_test.go

@@ -197,6 +197,9 @@ func TestParserErr(t *testing.T) {
 
 		test("\n/* Some multiline\ncomment */\n)", "(anonymous): Line 4:1 Unexpected token )")
 
+		test("+1 ** 2", "(anonymous): Line 1:4 Unexpected token **")
+		test("typeof 1 ** 2", "(anonymous): Line 1:10 Unexpected token **")
+
 		// TODO
 		//{ set 1 }
 		//{ get 2 }

+ 0 - 3
tc39_test.go

@@ -307,9 +307,6 @@ func init() {
 		"test/built-ins/GeneratorFunction/",
 		"test/built-ins/Function/prototype/toString/generator-",
 
-		// **
-		"test/language/expressions/exponentiation",
-
 		// BigInt
 		"test/built-ins/TypedArrayConstructors/BigUint64Array/",
 		"test/built-ins/TypedArrayConstructors/BigInt64Array/",

+ 4 - 0
token/token_const.go

@@ -13,6 +13,7 @@ const (
 	PLUS      // +
 	MINUS     // -
 	MULTIPLY  // *
+	EXPONENT  // **
 	SLASH     // /
 	REMAINDER // %
 
@@ -26,6 +27,7 @@ const (
 	ADD_ASSIGN       // +=
 	SUBTRACT_ASSIGN  // -=
 	MULTIPLY_ASSIGN  // *=
+	EXPONENT_ASSIGN  // **=
 	QUOTIENT_ASSIGN  // /=
 	REMAINDER_ASSIGN // %=
 
@@ -129,6 +131,7 @@ var token2string = [...]string{
 	IDENTIFIER:                  "IDENTIFIER",
 	PLUS:                        "+",
 	MINUS:                       "-",
+	EXPONENT:                    "**",
 	MULTIPLY:                    "*",
 	SLASH:                       "/",
 	REMAINDER:                   "%",
@@ -141,6 +144,7 @@ var token2string = [...]string{
 	ADD_ASSIGN:                  "+=",
 	SUBTRACT_ASSIGN:             "-=",
 	MULTIPLY_ASSIGN:             "*=",
+	EXPONENT_ASSIGN:             "**=",
 	QUOTIENT_ASSIGN:             "/=",
 	REMAINDER_ASSIGN:            "%=",
 	AND_ASSIGN:                  "&=",

+ 10 - 0
vm.go

@@ -994,6 +994,16 @@ end:
 	vm.pc++
 }
 
+type _exp struct{}
+
+var exp _exp
+
+func (_exp) exec(vm *vm) {
+	vm.sp--
+	vm.stack[vm.sp-1] = pow(vm.stack[vm.sp-1], vm.stack[vm.sp])
+	vm.pc++
+}
+
 type _div struct{}
 
 var div _div