Skip to content

Commit

Permalink
Implemented exponentiation expressions. Closes #381.
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Apr 22, 2022
1 parent ffe77e2 commit ff76422
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 39 deletions.
8 changes: 5 additions & 3 deletions builtin_math.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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())
}
Expand Down
7 changes: 7 additions & 0 deletions compiler_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
77 changes: 45 additions & 32 deletions parser/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -768,33 +789,31 @@ func (self *_parser) parseMultiplicativeExpression() ast.Expression {
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseExponentiationExpression(),
}
}

return left
}

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
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseMultiplicativeExpression(),
}
}

return left
}

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 {
Expand All @@ -803,16 +822,15 @@ func (self *_parser) parseShiftExpression() ast.Expression {
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseAdditiveExpression(),
}
}

return left
}

func (self *_parser) parseRelationalExpression() ast.Expression {
next := self.parseShiftExpression
left := next()
left := self.parseShiftExpression()

allowIn := self.scope.allowIn
self.scope.allowIn = true
Expand Down Expand Up @@ -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 {
Expand All @@ -865,7 +882,7 @@ func (self *_parser) parseEqualityExpression() ast.Expression {
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseRelationalExpression(),
Comparison: true,
}
}
Expand All @@ -874,84 +891,79 @@ 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
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseEqualityExpression(),
}
}

return left
}

func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
next := self.parseBitwiseAndExpression
left := next()
left := self.parseBitwiseAndExpression()

for self.token == token.EXCLUSIVE_OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseBitwiseAndExpression(),
}
}

return left
}

func (self *_parser) parseBitwiseOrExpression() ast.Expression {
next := self.parseBitwiseExclusiveOrExpression
left := next()
left := self.parseBitwiseExclusiveOrExpression()

for self.token == token.OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseBitwiseExclusiveOrExpression(),
}
}

return left
}

func (self *_parser) parseLogicalAndExpression() ast.Expression {
next := self.parseBitwiseOrExpression
left := next()
left := self.parseBitwiseOrExpression()

for self.token == token.LOGICAL_AND {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseBitwiseOrExpression(),
}
}

return left
}

func (self *_parser) parseLogicalOrExpression() ast.Expression {
next := self.parseLogicalAndExpression
left := next()
left := self.parseLogicalAndExpression()

for self.token == token.LOGICAL_OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Right: self.parseLogicalAndExpression(),
}
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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}
Expand All @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion parser/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
3 changes: 3 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
3 changes: 0 additions & 3 deletions tc39_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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/",
Expand Down
4 changes: 4 additions & 0 deletions token/token_const.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
PLUS // +
MINUS // -
MULTIPLY // *
EXPONENT // **
SLASH // /
REMAINDER // %

Expand All @@ -26,6 +27,7 @@ const (
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
MULTIPLY_ASSIGN // *=
EXPONENT_ASSIGN // **=
QUOTIENT_ASSIGN // /=
REMAINDER_ASSIGN // %=

Expand Down Expand Up @@ -129,6 +131,7 @@ var token2string = [...]string{
IDENTIFIER: "IDENTIFIER",
PLUS: "+",
MINUS: "-",
EXPONENT: "**",
MULTIPLY: "*",
SLASH: "/",
REMAINDER: "%",
Expand All @@ -141,6 +144,7 @@ var token2string = [...]string{
ADD_ASSIGN: "+=",
SUBTRACT_ASSIGN: "-=",
MULTIPLY_ASSIGN: "*=",
EXPONENT_ASSIGN: "**=",
QUOTIENT_ASSIGN: "/=",
REMAINDER_ASSIGN: "%=",
AND_ASSIGN: "&=",
Expand Down
10 changes: 10 additions & 0 deletions vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ff76422

Please sign in to comment.