Comparison operator support

This commit is contained in:
2023-04-04 00:48:28 -04:00
parent 16a205bea1
commit 67015c2ed9
2 changed files with 173 additions and 17 deletions

View File

@@ -8,16 +8,21 @@ This file sets out the various terms used to describe the
## Main Vocabulary Table
*Organized by least priority to most priority.*
```
expr : KEYWORD:set IDENTIFIER EQ expr
: term ((PLUS|MINUS) term)*
expr : KEYWORD:set IDENTIFIER EQ expr
: com-ex ((KEYWORD:AND|KEYWORD:OR) com-ex)*
term : factor ((MUL|DIV|POW) factor)*
com-expr : not com-ex
: ar-ex ((EE|LT|GT|LTE|GTE) ar-ex)*
factor : (PLUS|MINUS) factor
: power
ar-expr : term ((PLUS|MINUS) term)*
term : factor ((MUL|DIV|POW) factor)*
factor : (PLUS|MINUS) factor
: power
power : atom (POW factor)*
power : atom (POW factor)*
atom : INT|FLOAT|IDENTIFIER
: LPAREN expr RPAREN
atom : INT|FLOAT|IDENTIFIER
: LPAREN expr RPAREN
```

169
aurora.py
View File

@@ -44,6 +44,10 @@ class IllegalCharErr(Error):
super().__init__(pos_start, pos_end, 'IllegalCharacter', details)
class ExpectedCharErr(Error):
def __init__(self, pos_start, pos_end, details):
super().__init__(pos_start, pos_end, 'ExpectedCharacter', details)
class InvalidSyntaxErr(Error):
def __init__(self, pos_start, pos_end, details=''):
super().__init__(pos_start, pos_end, 'InvalidSyntax', details)
@@ -113,12 +117,21 @@ TT_MUL = "MUL"
TT_DIV = "DIV"
TT_POW = "POW"
TT_EQ = "EQ"
TT_EE = "EE"
TT_NE = "NE"
TT_LT = "LT"
TT_GT = "GT"
TT_LTE = "LTE"
TT_GTE = "GTE"
TT_LPAREN = "LPAREN"
TT_RPAREN = "RPAREN"
TT_EOF = "EOF"
KEYWORDS = [
'set'
'set',
'and',
'or',
'not'
]
@@ -186,15 +199,26 @@ class Lexer:
elif self.current_char == '^':
tokens.append(Token(TT_POW, pos_start=self.pos))
self.advance()
elif self.current_char == '=':
tokens.append(Token(TT_EQ, pos_start=self.pos))
self.advance()
elif self.current_char == '(':
tokens.append(Token(TT_LPAREN, pos_start=self.pos))
self.advance()
elif self.current_char == ')':
tokens.append(Token(TT_RPAREN, pos_start=self.pos))
self.advance()
elif self.current_char == '!':
token, error = self.make_not_equals()
if error:
return [], error
tokens.append(token)
elif self.current_char == '=':
tokens.append(self.make_equals())
self.advance()
elif self.current_char == '<':
tokens.append(self.make_lt())
self.advance()
elif self.current_char == '>':
tokens.append(self.make_gt())
self.advance()
else:
pos_start = self.pos.copy()
char = self.current_char
@@ -235,6 +259,50 @@ class Lexer:
token_type = TT_KEYWORD if id_string in KEYWORDS else TT_IDENTIFIER
return Token(token_type, id_string, pos_start, self.pos)
def make_not_equals(self):
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
return Token(TT_NE, pos_start=pos_start, pos_end=self.pos), None
self.advance()
return None, ExpectedCharErr(pos_start, self.pos, "'=' after '!'")
def make_equals(self):
token_type = TT_EQ
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
token_type = TT_EE
return Token(token_type, pos_start=pos_start, pos_end=self.pos)
def make_lt(self):
token_type = TT_LT
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
token_type = TT_LTE
return Token(token_type, pos_start=pos_start, pos_end=self.pos)
def make_gt(self):
token_type = TT_GT
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
token_type = TT_GTE
return Token(token_type, pos_start=pos_start, pos_end=self.pos)
####################
# NODES
@@ -359,7 +427,7 @@ class Parser:
return result.failure(InvalidSyntaxErr(
self.current_token.pos_start,
self.current_token.pos_end,
"Expected '+', '-', '*','/', or '^'"
"Expected '+', '-', '*', '/', or '^'"
))
return result
@@ -417,6 +485,32 @@ class Parser:
def term(self):
return self.binary_operation(self.factor, (TT_MUL, TT_DIV, TT_POW))
def ar_expr(self):
return self.binary_operation(self.term, (TT_PLUS, TT_MINUS))
def com_expr(self):
result = ParsedResult()
if self.current_token.matches(TT_KEYWORD, 'not'):
operation = self.current_token
result.register_advancement()
self.advance()
node = result.register(self.com_expr())
if result.error:
return result
return result.success(UnaryOperationNode(operation, node))
node = result.register(self.binary_operation(self.ar_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE, TT_GTE)))
if result.error:
return result.failure(InvalidSyntaxErr(
self.current_token.pos_start,
self.current_token.pos_end,
"Expected int, float, identifier, '+', '-', '(', or 'not'"
))
return result.success(node)
def expr(self):
result = ParsedResult()
@@ -449,12 +543,12 @@ class Parser:
return result
return result.success(VarAssignNode(var_name, expr))
node = result.register(self.binary_operation(self.term, (TT_PLUS, TT_MINUS)))
node = result.register(self.binary_operation(self.com_expr, ((TT_KEYWORD, "and"), (TT_KEYWORD, "or"))))
if result.error:
return result.failure(InvalidSyntaxErr(
self.current_token.pos_start,
self.current_token.pos_end,
"Expected 'set', int, float, identifier, '+', '-' or '('"
"Expected 'set', int, float, identifier, '+', '-', '(', or 'not'"
))
return result.success(node)
@@ -466,7 +560,8 @@ class Parser:
if result.error:
return result
while self.current_token.type in operations:
while self.current_token.type in operations or \
(self.current_token.type, self.current_token.value) in operations:
operation = self.current_token
result.register_advancement()
self.advance()
@@ -524,6 +619,41 @@ class Number:
if isinstance(other, Number):
return Number(self.value ** other.value).set_context(self.context), None
def comp_eq(self, other):
if isinstance(other, Number):
return Number(int(self.value == other.value)).set_context(self.context), None
def comp_ne(self, other):
if isinstance(other, Number):
return Number(int(self.value != other.value)).set_context(self.context), None
def comp_lt(self, other):
if isinstance(other, Number):
return Number(int(self.value < other.value)).set_context(self.context), None
def comp_gt(self, other):
if isinstance(other, Number):
return Number(int(self.value > other.value)).set_context(self.context), None
def comp_lte(self, other):
if isinstance(other, Number):
return Number(int(self.value <= other.value)).set_context(self.context), None
def comp_gte(self, other):
if isinstance(other, Number):
return Number(int(self.value >= other.value)).set_context(self.context), None
def comp_and(self, other):
if isinstance(other, Number):
return Number(int(self.value and other.value)).set_context(self.context), None
def comp_or(self, other):
if isinstance(other, Number):
return Number(int(self.value or other.value)).set_context(self.context), None
def not_op(self):
return Number(1 if self.value == 0 else 0).set_context(self.context), None
def copy(self):
copy = Number(self.value)
copy.set_pos(self.pos_start, self.pos_end)
@@ -610,6 +740,7 @@ class Interpreter:
return result.success(value)
def visit_BinaryOperationNode(self, node, context):
result = error = None
rt_result = RuntimeResult()
left = rt_result.register(self.visit(node.left_node, context))
if rt_result.error:
@@ -628,6 +759,22 @@ class Interpreter:
result, error = left.divided_by(right)
elif node.operation.type == TT_POW:
result, error = left.power_of(right)
elif node.operation.type == TT_EE:
result, error = left.comp_eq(right)
elif node.operation.type == TT_NE:
result, error = left.comp_ne(right)
elif node.operation.type == TT_LT:
result, error = left.comp_lt(right)
elif node.operation.type == TT_GT:
result, error = left.comp_gt(right)
elif node.operation.type == TT_LTE:
result, error = left.comp_lte(right)
elif node.operation.type == TT_GTE:
result, error = left.comp_gte(right)
elif node.operation.matches(TT_KEYWORD, 'and'):
result, error = left.comp_and(right)
elif node.operation.matches(TT_KEYWORD, 'or'):
result, error = left.comp_or(right)
if error:
return rt_result.failure(error)
@@ -641,10 +788,12 @@ class Interpreter:
if node.operation.type == TT_MINUS:
number, error = number.multiplied_by(Number(-1))
elif node.operation.matches(TT_KEYWORD, 'not'):
number, error = number.not_op()
if error:
return result.failure(error)
return number.set_pos(node.pos_start, node.pos_end)
return result.success(number.set_pos(node.pos_start, node.pos_end))
####################
@@ -652,6 +801,8 @@ class Interpreter:
####################
global_symbol_table = SymbolTable()
global_symbol_table.set("null", Number(0))
global_symbol_table.set("true", Number(1))
global_symbol_table.set("false", Number(0))
def evaluate(fn, text):