Add power operator

This commit is contained in:
2023-04-03 19:53:19 -04:00
parent b7f3867196
commit fd2e2cf144
2 changed files with 50 additions and 20 deletions

View File

@@ -9,9 +9,13 @@ This file sets out the various terms used to describe the
``` ```
expr : term ((PLUS|MINUS) term)* expr : term ((PLUS|MINUS) term)*
term : factor ((MUL|DIV) factor)* term : factor ((MUL|DIV|POW) factor)*
factor : INT | FLOAT factor : (PLUS|MINUS) factor
: (PLUS|MINUS) factor : power
power : atom (POW factor)*
atom : INT | FLOAT
: LPAREN expr RPAREN : LPAREN expr RPAREN
``` ```

View File

@@ -106,6 +106,7 @@ TT_PLUS = "PLUS"
TT_MINUS = "MINUS" TT_MINUS = "MINUS"
TT_MUL = "MUL" TT_MUL = "MUL"
TT_DIV = "DIV" TT_DIV = "DIV"
TT_POW = "POW"
TT_LPAREN = "LPAREN" TT_LPAREN = "LPAREN"
TT_RPAREN = "RPAREN" TT_RPAREN = "RPAREN"
TT_EOF = "EOF" TT_EOF = "EOF"
@@ -167,6 +168,9 @@ class Lexer:
elif self.current_char == '/': elif self.current_char == '/':
tokens.append(Token(TT_DIV, pos_start=self.pos)) tokens.append(Token(TT_DIV, pos_start=self.pos))
self.advance() self.advance()
elif self.current_char == '^':
tokens.append(Token(TT_POW, pos_start=self.pos))
self.advance()
elif self.current_char == '(': elif self.current_char == '(':
tokens.append(Token(TT_LPAREN, pos_start=self.pos)) tokens.append(Token(TT_LPAREN, pos_start=self.pos))
self.advance() self.advance()
@@ -307,21 +311,15 @@ class Parser:
return result.failure(InvalidSyntaxErr( return result.failure(InvalidSyntaxErr(
self.current_token.pos_start, self.current_token.pos_start,
self.current_token.pos_end, self.current_token.pos_end,
"Expected '+', '-', '*', or '/'" "Expected '+', '-', '*','/', or '^'"
)) ))
return result return result
def factor(self): def atom(self):
result = ParsedResult() result = ParsedResult()
token = self.current_token token = self.current_token
if token.type in (TT_PLUS, TT_MINUS): if token.type in (TT_INT, TT_FLOAT):
result.register(self.advance())
factor = result.register(self.factor())
if result.error:
return result
return result.success(UnaryOperationNode(token, factor))
elif token.type in (TT_INT, TT_FLOAT):
result.register(self.advance()) result.register(self.advance())
return result.success(NumberNode(token)) return result.success(NumberNode(token))
elif token.type == TT_LPAREN: elif token.type == TT_LPAREN:
@@ -338,24 +336,46 @@ class Parser:
"Expected ')'" "Expected ')'"
)) ))
return result.failure(InvalidSyntaxErr(token.pos_start, token.pos_end, "Expected int or float")) return result.failure(InvalidSyntaxErr(
token.pos_start,
token.pos_end,
"Exprected int, float, '+', '-', or '('"
))
def power(self):
return self.binary_operation(self.atom, (TT_POW, ), self.factor)
def factor(self):
result = ParsedResult()
token = self.current_token
if token.type in (TT_PLUS, TT_MINUS):
result.register(self.advance())
factor = result.register(self.factor())
if result.error:
return result
return result.success(UnaryOperationNode(token, factor))
return self.power()
def term(self): def term(self):
return self.binary_operation(self.factor, (TT_MUL, TT_DIV)) return self.binary_operation(self.factor, (TT_MUL, TT_DIV, TT_POW))
def expr(self): def expr(self):
return self.binary_operation(self.term, (TT_PLUS, TT_MINUS)) return self.binary_operation(self.term, (TT_PLUS, TT_MINUS))
def binary_operation(self, func, operations): def binary_operation(self, lfunc, operations, rfunc=None):
if rfunc is None:
rfunc = lfunc
result = ParsedResult() result = ParsedResult()
left = result.register(func()) left = result.register(lfunc())
if result.error: if result.error:
return result return result
while self.current_token.type in operations: while self.current_token.type in operations:
operation = self.current_token operation = self.current_token
result.register(self.advance()) result.register(self.advance())
right = result.register(func()) right = result.register(rfunc())
if result.error: if result.error:
return result return result
left = BinaryOperationNode(left, operation, right) left = BinaryOperationNode(left, operation, right)
@@ -405,6 +425,10 @@ class Number:
) )
return Number(self.value / other.value).set_context(self.context), None return Number(self.value / other.value).set_context(self.context), None
def power_of(self, other):
if isinstance(other, Number):
return Number(self.value ** other.value).set_context(self.context), None
def __repr__(self): def __repr__(self):
return str(self.value) return str(self.value)
@@ -445,12 +469,14 @@ class Interpreter:
if node.operation.type == TT_PLUS: if node.operation.type == TT_PLUS:
result, error = left.added_to(right) result, error = left.added_to(right)
if node.operation.type == TT_MINUS: elif node.operation.type == TT_MINUS:
result, error = left.subtracted_by(right) result, error = left.subtracted_by(right)
if node.operation.type == TT_MUL: elif node.operation.type == TT_MUL:
result, error = left.multiplied_by(right) result, error = left.multiplied_by(right)
if node.operation.type == TT_DIV: elif node.operation.type == TT_DIV:
result, error = left.divided_by(right) result, error = left.divided_by(right)
elif node.operation.type == TT_POW:
result, error = left.power_of(right)
if error: if error:
return rt_result.failure(error) return rt_result.failure(error)