diff options
| author | Andrew <saintruler@gmail.com> | 2021-07-12 16:57:10 +0400 |
|---|---|---|
| committer | Andrew <saintruler@gmail.com> | 2021-07-12 16:59:08 +0400 |
| commit | f078f93ba357c3ede0b109a3b9ea5e79c7a8b777 (patch) | |
| tree | 132c9d46ce508e6f4a0c31300b8d95bec89d4803 | |
| parent | 49df60f32aca6428706bc895b7e48ab2d68444b5 (diff) | |
Added ability to call functions as a statement.
| -rw-r--r-- | consts.py | 2 | ||||
| -rw-r--r-- | main.py | 14 | ||||
| -rw-r--r-- | parser.py | 99 |
3 files changed, 99 insertions, 16 deletions
@@ -13,7 +13,7 @@ class TokenType: class NodeType: ( - NUMBER, OPERATOR, SYMBOL, FUNCALL, UNARY, ASSIGNMENT, *_ + NUMBER, OPERATOR, SYMBOL, FUNCALL, ARGUMENTS, UNARY, ASSIGNMENT, *_ ) = range(100) @@ -31,7 +31,8 @@ def factorial(n): runtime_functions = { - "factorial": factorial + "factorial": factorial, + "print": print, } # END OF RUNTIME @@ -45,8 +46,8 @@ def _eval(node): return runtime.get(node.value) elif node.type == NodeType.FUNCALL: - fun_name = node.value[0] - args = list(map(_eval, node.value[1])) + fun_name = node.left.value + args = list(map(_eval, node.right.value)) return runtime_functions.get(fun_name)(*args) elif node.type == NodeType.OPERATOR: @@ -64,9 +65,10 @@ def main(*argv): data = argv[0] else: # data = "2 + 3 * 4" - data = "let a = 2 + 3; let e = 4;" + # data = "let a = 2 + 3; let e = 4;" # data = "(3 + 3 * 2) * -4" # data = "(2 + factorial(4, )) * 9" + data = "print(2);" tokens = tokenize(data) # print(tokens) @@ -74,8 +76,8 @@ def main(*argv): for statement in statements: _eval(statement) # node, _ = parse_expr(tokens, 0) - # print(expr_eval(node)) - print(1) + # print(_eval(node)) + pass if __name__ == "__main__": @@ -7,7 +7,7 @@ class ParserError(Exception): class Node: - def __init__(self, node_type, value=None, subtype=None): + def __init__(self, node_type, *, value=None, subtype=None): self.type = node_type self.value = value self.subtype = subtype @@ -50,7 +50,7 @@ def parse_parenthesis(tokens, start): if depth == 0 and token.type == TokenType.RIGHT_PARENTHESIS: break end += 1 - node = parse_expr(tokens[start + 1: end]) + node, _ = parse_expr(tokens[start + 1: end], 0) return node, end @@ -78,7 +78,11 @@ def parse_args(tokens, start): if len(arg) != 0: args.append(arg) - return list(map(parse_expr, args)) + tmp = [] + for arg in args: + node, _ = parse_expr(arg, 0) + tmp.append(node) + return tmp def parse_expr(tokens, start): @@ -91,7 +95,8 @@ def parse_expr(tokens, start): if state == State.OPERATOR and token.type == TokenType.LEFT_PARENTHESIS: args = parse_args(tokens, i) current_node.type = NodeType.FUNCALL - current_node.value = (current_node.value, args) + current_node.left = Node(NodeType.SYMBOL, value=current_node.value) + current_node.right = Node(NodeType.ARGUMENTS, value=args) elif token.type in [TokenType.LEFT_PARENTHESIS, TokenType.NUMBER, TokenType.SYMBOL] or token.subtype == TokenType.UNARY: @@ -146,7 +151,7 @@ def parse_expr(tokens, start): raise ValueError("Not a valid expression") state = State.NAME - elif token.type == TokenType.SEMICOLON: + elif token.type in [TokenType.SEMICOLON, TokenType.COMMA]: break i += 1 @@ -205,18 +210,94 @@ def parse_let_statement(tokens: list[Token], start: int): return root_node, i +def parse_function_call(tokens: list[Token], start: int): + class FuncStates: + (WAIT_SYMBOL, WAIT_LEFT_PAR, PARSING_EXPR, WAIT_SEMICOLON, PARSE_END, *_) = range(100) + + root_node = Node(NodeType.FUNCALL) + state = FuncStates.WAIT_SYMBOL + i = start + args = [] + arg = [] + + while i < len(tokens): + token = tokens[i] + if state == FuncStates.WAIT_SYMBOL: + if token.type == TokenType.SYMBOL: + root_node.left = Node(NodeType.SYMBOL, value=token.value) + state = FuncStates.WAIT_LEFT_PAR + else: + raise ParserError(f"Waited for symbol, got {token}") + + elif state == FuncStates.WAIT_LEFT_PAR: + if token.type == TokenType.LEFT_PARENTHESIS: + state = FuncStates.PARSING_EXPR + else: + raise ParserError(f"Waited for left parenthesis, got {token}") + + elif state == FuncStates.PARSING_EXPR: + if token.type == TokenType.COMMA: + node, _ = parse_expr(arg, 0) + args.append(node) + arg.clear() + elif token.type == TokenType.RIGHT_PARENTHESIS: + node, _ = parse_expr(arg, 0) + args.append(node) + root_node.right = Node(NodeType.ARGUMENTS, value=args) + state = FuncStates.WAIT_SEMICOLON + else: + arg.append(token) + + elif state == FuncStates.WAIT_SEMICOLON: + if token.type == TokenType.SEMICOLON: + state = FuncStates.PARSE_END + break + else: + raise ParserError(f"Waited for semicolon, got {token}") + + i += 1 + + if state != FuncStates.PARSE_END: + raise ParserError("Statement ended unexpectedly") + + return root_node, i + + def parse(tokens: list[Token]): + class ParseState: + (ANY, GOT_SYMBOL, *_) = range(100) + _statements = [ [Keyword.LET, TokenType.SYMBOL, TokenType.EQUALS, "EXPR", TokenType.SEMICOLON], - [Keyword.FN, TokenType.SYMBOL, TokenType.LEFT_PARENTHESIS, "ARGS", TokenType.RIGHT_PARENTHESIS, TokenType.LEFT_BRACE, ["STATEMENTS"], TokenType.RIGHT_BRACE], + [TokenType.SYMBOL, TokenType.EQUALS, "EXPR", TokenType.SEMICOLON], + [TokenType.SYMBOL, TokenType.LEFT_PARENTHESIS, "ARGS", TokenType.RIGHT_PARENTHESIS, TokenType.SEMICOLON], + [Keyword.FN, TokenType.SYMBOL, TokenType.LEFT_PARENTHESIS, "ARGS", TokenType.RIGHT_PARENTHESIS, TokenType.LEFT_BRACE, ["STATEMENT"], TokenType.RIGHT_BRACE], ] + state = ParseState.ANY + statements = [] + symbol = None i = 0 while i < len(tokens): - if tokens[i].type == TokenType.KEYWORD and tokens[i].subtype == Keyword.LET: - node, i = parse_let_statement(tokens, i) - statements.append(node) + token = tokens[i] + + if state == ParseState.ANY: + if token.type == TokenType.KEYWORD: + if token.subtype == Keyword.LET: + node, i = parse_let_statement(tokens, i) + statements.append(node) + elif token.type == TokenType.SYMBOL: + state = ParseState.GOT_SYMBOL + + elif state == ParseState.GOT_SYMBOL: + if token.type == TokenType.LEFT_PARENTHESIS: + node, i = parse_function_call(tokens, i - 1) + statements.append(node) + state = ParseState.ANY + else: + raise ParserError("oops...") + i += 1 return statements |