mirror of
https://github.com/Zandercraft/Aurora-lang.git
synced 2026-10-29 04:39:21 +00:00
Add for and while loops
This commit is contained in:
@@ -3,30 +3,45 @@ This file sets out the various terms used to describe the
|
|||||||
|
|
||||||
## Legend
|
## Legend
|
||||||
`|` - or
|
`|` - or
|
||||||
`*`- zero or more of the thing before it
|
`*`- zero or more of the thing before it
|
||||||
|
`?` - optional
|
||||||
|
|
||||||
## Main Vocabulary Table
|
## Main Vocabulary Table
|
||||||
*Organized by least priority to most priority.*
|
*Organized by least priority to most priority.*
|
||||||
```
|
```
|
||||||
expr : KEYWORD:set IDENTIFIER EQ expr
|
expr : KEYWORD:set IDENTIFIER EQ expr
|
||||||
: com-ex ((KEYWORD:AND|KEYWORD:OR) com-ex)*
|
: com-ex ((KEYWORD:AND|KEYWORD:OR) com-ex)*
|
||||||
|
|
||||||
com-expr : not com-ex
|
com-expr : not com-ex
|
||||||
: ar-ex ((EE|LT|GT|LTE|GTE) ar-ex)*
|
: ar-ex ((EE|LT|GT|LTE|GTE) ar-ex)*
|
||||||
|
|
||||||
ar-expr : term ((PLUS|MINUS) term)*
|
ar-expr : term ((PLUS|MINUS) term)*
|
||||||
|
|
||||||
term : factor ((MUL|DIV|POW) factor)*
|
term : factor ((MUL|DIV|POW) factor)*
|
||||||
|
|
||||||
factor : (PLUS|MINUS) factor
|
factor : (PLUS|MINUS) factor
|
||||||
: power
|
: power
|
||||||
|
|
||||||
power : atom (POW factor)*
|
power : call (POW factor)*
|
||||||
|
|
||||||
atom : INT|FLOAT|IDENTIFIER
|
call : atom (LPAREN (expr (COMMA expr)*)? RPAREN)?
|
||||||
: LPAREN expr RPAREN
|
|
||||||
|
atom : INT|FLOAT|IDENTIFIER
|
||||||
|
: LPAREN expr RPAREN
|
||||||
|
: for-expr
|
||||||
|
: while-expr
|
||||||
|
: fun-def
|
||||||
|
|
||||||
if-expr : KEYWORD:if expr KEYWORD:then expr
|
if-expr : KEYWORD:if expr KEYWORD:then expr
|
||||||
(KEYWORD:eli expr KEYWORD:then expr)*
|
(KEYWORD:eli expr KEYWORD:then expr)?*
|
||||||
(KEYWORD:el expr)
|
(KEYWORD:el expr)?
|
||||||
|
|
||||||
|
for-expr : KEYWORD:for IDENTIFIER EQ expr KEYWORD:TO expr
|
||||||
|
(KEYWORD:step expr)? KEYWORD:then expr
|
||||||
|
|
||||||
|
while-expr : KEYWORD:while expr KEYWORD then expr
|
||||||
|
|
||||||
|
fun-def : KEYWORD:fun IDENTIFIER?
|
||||||
|
LPAREN (IDENTIFIER (COMMA IDENTIFIER)*)? RPAREN
|
||||||
|
ARROW expr
|
||||||
```
|
```
|
||||||
|
|||||||
217
aurora.py
217
aurora.py
@@ -125,6 +125,8 @@ TT_LTE = "LTE"
|
|||||||
TT_GTE = "GTE"
|
TT_GTE = "GTE"
|
||||||
TT_LPAREN = "LPAREN"
|
TT_LPAREN = "LPAREN"
|
||||||
TT_RPAREN = "RPAREN"
|
TT_RPAREN = "RPAREN"
|
||||||
|
TT_COMMA = "COMMA"
|
||||||
|
TT_ARROW = "ARROW"
|
||||||
TT_EOF = "EOF"
|
TT_EOF = "EOF"
|
||||||
|
|
||||||
KEYWORDS = [
|
KEYWORDS = [
|
||||||
@@ -135,7 +137,12 @@ KEYWORDS = [
|
|||||||
'if',
|
'if',
|
||||||
'then',
|
'then',
|
||||||
'eli',
|
'eli',
|
||||||
'else'
|
'else',
|
||||||
|
'for',
|
||||||
|
'to',
|
||||||
|
'step',
|
||||||
|
'while',
|
||||||
|
'fun'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -192,8 +199,7 @@ class Lexer:
|
|||||||
tokens.append(Token(TT_PLUS, pos_start=self.pos))
|
tokens.append(Token(TT_PLUS, pos_start=self.pos))
|
||||||
self.advance()
|
self.advance()
|
||||||
elif self.current_char == '-':
|
elif self.current_char == '-':
|
||||||
tokens.append(Token(TT_MINUS, pos_start=self.pos))
|
tokens.append(self.make_dash_operators())
|
||||||
self.advance()
|
|
||||||
elif self.current_char == '*':
|
elif self.current_char == '*':
|
||||||
tokens.append(Token(TT_MUL, pos_start=self.pos))
|
tokens.append(Token(TT_MUL, pos_start=self.pos))
|
||||||
self.advance()
|
self.advance()
|
||||||
@@ -223,6 +229,9 @@ class Lexer:
|
|||||||
elif self.current_char == '>':
|
elif self.current_char == '>':
|
||||||
tokens.append(self.make_gt())
|
tokens.append(self.make_gt())
|
||||||
self.advance()
|
self.advance()
|
||||||
|
elif self.current_char == ',':
|
||||||
|
tokens.append(Token(TT_COMMA, pos_start=self.pos))
|
||||||
|
self.advance()
|
||||||
else:
|
else:
|
||||||
pos_start = self.pos.copy()
|
pos_start = self.pos.copy()
|
||||||
char = self.current_char
|
char = self.current_char
|
||||||
@@ -252,6 +261,17 @@ class Lexer:
|
|||||||
else:
|
else:
|
||||||
return Token(TT_FLOAT, float(num_str), pos_start, self.pos)
|
return Token(TT_FLOAT, float(num_str), pos_start, self.pos)
|
||||||
|
|
||||||
|
def make_dash_operators(self):
|
||||||
|
token_type = TT_MINUS
|
||||||
|
pos_start = self.pos.copy()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
if self.current_char == '>':
|
||||||
|
self.advance()
|
||||||
|
token_type = TT_ARROW
|
||||||
|
|
||||||
|
return Token(token_type, pos_start=pos_start, pos_end=self.pos)
|
||||||
|
|
||||||
def make_identifier(self):
|
def make_identifier(self):
|
||||||
id_string = ''
|
id_string = ''
|
||||||
pos_start = self.pos.copy()
|
pos_start = self.pos.copy()
|
||||||
@@ -367,6 +387,25 @@ class IfNode:
|
|||||||
self.pos_end = (self.else_case or self.cases[len(self.cases) - 1][0]).pos_end
|
self.pos_end = (self.else_case or self.cases[len(self.cases) - 1][0]).pos_end
|
||||||
|
|
||||||
|
|
||||||
|
class ForNode:
|
||||||
|
def __init__(self, var_name_token, start_value_node, end_value_node, step_value_node, body_node):
|
||||||
|
self.var_name_token = var_name_token
|
||||||
|
self.start_value_node = start_value_node
|
||||||
|
self.end_value_node = end_value_node
|
||||||
|
self.step_value_node = step_value_node
|
||||||
|
self.body_node = body_node
|
||||||
|
self.pos_start = self.var_name_token.pos_start
|
||||||
|
self.pos_end = self.body_node.pos_end
|
||||||
|
|
||||||
|
|
||||||
|
class WhileNode:
|
||||||
|
def __init__(self, condition_node, body_node):
|
||||||
|
self.condition_node = condition_node
|
||||||
|
self.body_node = body_node
|
||||||
|
self.pos_start = condition_node.pos_start
|
||||||
|
self.pos_end = body_node.pos_end
|
||||||
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# PARSER RESULT
|
# PARSER RESULT
|
||||||
####################
|
####################
|
||||||
@@ -476,7 +515,18 @@ class Parser:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
return result.success(if_expr)
|
return result.success(if_expr)
|
||||||
|
elif token.matches(TT_KEYWORD, 'for'):
|
||||||
|
for_expr = result.register(self.for_expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(for_expr)
|
||||||
|
elif token.matches(TT_KEYWORD, 'while'):
|
||||||
|
while_expr = result.register(self.while_expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(while_expr)
|
||||||
return result.failure(InvalidSyntaxErr(
|
return result.failure(InvalidSyntaxErr(
|
||||||
token.pos_start,
|
token.pos_start,
|
||||||
token.pos_end,
|
token.pos_end,
|
||||||
@@ -636,6 +686,116 @@ class Parser:
|
|||||||
return result
|
return result
|
||||||
return result.success(IfNode(cases, else_case))
|
return result.success(IfNode(cases, else_case))
|
||||||
|
|
||||||
|
def for_expr(self):
|
||||||
|
result = ParsedResult()
|
||||||
|
|
||||||
|
if not self.current_token.matches(TT_KEYWORD, 'for'):
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected 'for'"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
if self.current_token.type != TT_IDENTIFIER:
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected identifier"
|
||||||
|
))
|
||||||
|
|
||||||
|
var_name = self.current_token
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
if self.current_token.type != TT_EQ:
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected '='"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
start_value = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not self.current_token.matches(TT_KEYWORD, 'to'):
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected 'to'"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
end_value = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
step_value = None
|
||||||
|
if self.current_token.matches(TT_KEYWORD, 'step'):
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
step_value = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not self.current_token.matches(TT_KEYWORD, 'then'):
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected 'then'"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
body = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(ForNode(var_name, start_value, end_value, step_value, body))
|
||||||
|
|
||||||
|
def while_expr(self):
|
||||||
|
result = ParsedResult()
|
||||||
|
|
||||||
|
if not self.current_token.matches(TT_KEYWORD, 'while'):
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected 'while'"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
condition = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not self.current_token.matches(TT_KEYWORD, 'then'):
|
||||||
|
return result.failure(InvalidSyntaxErr(
|
||||||
|
self.current_token.pos_start,
|
||||||
|
self.current_token.pos_end,
|
||||||
|
"Expected 'then'"
|
||||||
|
))
|
||||||
|
|
||||||
|
result.register_advancement()
|
||||||
|
self.advance()
|
||||||
|
|
||||||
|
body = result.register(self.expr())
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(WhileNode(condition, body))
|
||||||
|
|
||||||
def binary_operation(self, lfunc, operations, rfunc=None):
|
def binary_operation(self, lfunc, operations, rfunc=None):
|
||||||
if rfunc is None:
|
if rfunc is None:
|
||||||
rfunc = lfunc
|
rfunc = lfunc
|
||||||
@@ -906,6 +1066,57 @@ class Interpreter:
|
|||||||
|
|
||||||
return result.success(None)
|
return result.success(None)
|
||||||
|
|
||||||
|
def visit_ForNode(self, node: ForNode, context: Context):
|
||||||
|
result = RuntimeResult()
|
||||||
|
|
||||||
|
start_value = result.register(self.visit(node.start_value_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
end_value = result.register(self.visit(node.end_value_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
step_value = Number(1)
|
||||||
|
if node.step_value_node:
|
||||||
|
step_value = result.register(self.visit(node.step_value_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
i = start_value.value
|
||||||
|
|
||||||
|
if step_value.value >= 0:
|
||||||
|
condition = lambda: i < end_value.value
|
||||||
|
else:
|
||||||
|
condition = lambda: i > end_value.value
|
||||||
|
|
||||||
|
while condition():
|
||||||
|
context.symbol_table.set(node.var_name_token.value, Number(i))
|
||||||
|
i += step_value.value
|
||||||
|
|
||||||
|
result.register(self.visit(node.body_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(None)
|
||||||
|
|
||||||
|
def visit_WhileNode(self, node: WhileNode, context: Context):
|
||||||
|
result = RuntimeResult()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
condition = result.register(self.visit(node.condition_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not condition.is_true():
|
||||||
|
break
|
||||||
|
|
||||||
|
result.register(self.visit(node.body_node, context))
|
||||||
|
if result.error:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return result.success(None)
|
||||||
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# RUNNER
|
# RUNNER
|
||||||
|
|||||||
Reference in New Issue
Block a user