diff options
| -rw-r--r-- | parser.py | 176 | ||||
| -rw-r--r-- | repl.py | 6 |
2 files changed, 106 insertions, 76 deletions
@@ -1,86 +1,112 @@ -from tokens import * +from lexer import TokenType +class Expr: -def peek(inp): - if len(inp) == 0: - return None - return inp[0] + def accept(self, visitor): + raise Exception("needs to be implemented") -def parse_expression(tkns): - symbol = None - args = [] - add_idx = 0 - for idx, t in enumerate(tkns): - # if we evaluated a nested expression, skip ahead - # TODO or list? - if add_idx > 0: - add_idx -= 1 - continue - if idx == 0: - if not isinstance(t, NebSymbol): - raise Exception("expressions must start with a symbol") - else: - symbol = t - elif isinstance(t, NebClose): - return NebExpression(symbol, args), tkns[idx + 1:], idx + 1 + class Literal: + def __init__(self, value): + self.value = value + def accept(self, visitor): + visitor.visitLiteral(self) + def __str__(self): + return f"{self.value}" - # nested expressions - elif isinstance(t, NebOpen): - expr, remainder, add_idx = parse_expression(tkns[idx + 1:]) - args.append(expr) + class Symbol: + def __init__(self, name): + self.name = name + def accept(self, visitor): + visitor.visitSymbol(self) + def __str__(self): + return f"'{self.name}" - elif isinstance(t, NebListStart): - # TODO this might need to be add_idx + (return of parse_list) - lst, remainder, add_idx = parse_list(tkns[idx + 1:]) - args.append(lst) + class Nary: + def __init__(self, symbol, args): + self.symbol = symbol + self.args = args + def accept(self, visitor): + visitor.visitNary(self) + def __str__(self): + out = f"[{self.symbol} => (" + first = True + for arg in self.args: + if first: + out = f"{out} {arg}" + first = False + else: + out = f"{out}, {arg}" + return f"{out} )]" - else: - args.append(t) - - raise Exception("couldn't parse expression!") + class Binary: + def __init__(self, symbol, left, right): + self.symbol = symbol + self.left = left + self.right = right + def accept(self, visitor): + visitor.visitBinary(self) -def parse_list(tkns): - items = [] - add_idx = 0 - for idx, t in enumerate(tkns): - if add_idx > 0: - add_idx -= 1 - continue +class Visitor: + def visitLiteral(self, literal): + return literal.value + def visitBinary(self, binary): + sym = binary.symbol.text + left = binary.left.accept(self) + right = binary.right.accept(self) + return "({sym} {left} {right}" + def visitNary(self, nary): + sym = nary.symbol.text + args = [] + for arg in nary.args: + args.append(arg.accept(self)) + return "({sym} {' '.join(args)})" + def visitSymbol(self, symbol): + return symbol.name + +def parseExpression(token, prev, tokens): + idx = 0 + args = [] + prev = token + while tokens[idx].type_ != TokenType.CLOSE_PAREN: + token = tokens[idx] + inc = 1 + if token.type_ == TokenType.OPEN_PAREN: + expr, inc = parseExpression(token, prev, tokens[idx+1:]) + args.append(expr) + elif token.type_ in (TokenType.STRING, TokenType.TRUE, TokenType.FALSE, TokenType.INT, TokenType.FLOAT): + expr, inc = parseLiteral(token, prev, tokens[idx+1:]) + args.append(expr) + else: + expr, inc = parseSymbol(token, prev, tokens[idx+1:]) + args.append(expr) + idx += inc + prev = token + + return Expr.Nary(args[0], args[1:]), idx + 2 # parens - if isinstance(t, NebListEnd): - return NebList(items), tkns[idx + 1:], idx + 1 - elif isinstance(t, NebOpen): - expr, remainder, add_idx = parse_expression(tkns[1 + idx:]) - items.append(expr) - elif isinstance(t, NebLiteral): - items.append(t) - elif isinstance(t, NebSymbol): - items.append(t) - elif isinstance(t, NebListStart): - # TODO: this probably means lists of lists don't work - lst, remainder, add_idx = parse_list(tkns[1:]) - items.append(lst) +def parseSymbol(token, prev, tokens): + return Expr.Symbol(token.text), 1 - raise Exception("couldn't parse list!") +def parseLiteral(token, prev, tokens): + return Expr.Literal(token.value), 1 -def parse(tkns, parsed): - nxt = peek(tkns) - if nxt is None: - return parsed - if isinstance(nxt, NebOpen): - expr, remainder, _ = parse_expression(tkns[1:]) - parsed.append(expr) - return parse(remainder, parsed) - elif isinstance(nxt, NebListStart): - lst, remainder, _ = parse_list(tkns[1:]) - parsed.append(lst) - return parse(remainder, parsed) - elif isinstance(nxt, NebLiteral): - parsed.append(nxt) - return parse(tkns[1:], parsed) - elif isinstance(nxt, NebSymbol): - parsed.append(nxt) - return parse(tkns[1:], parsed) - else: - raise Exception("expecting an expression or a literal") +def parse(tokens): + idx = 0 + prev = None + exprs = [] + while tokens[idx].type_ != TokenType.EOF: + token = tokens[idx] + counter = 1 + if token.type_ == TokenType.OPEN_PAREN: + expr, counter = parseExpression(token, prev, tokens[idx+1:]) + exprs.append(expr) + elif token.type_ in (TokenType.FALSE, TokenType.TRUE, TokenType.STRING, TokenType.INT, TokenType.FLOAT): + lit, counter = parseLiteral(token, prev, tokens[idx+1:]) + exprs.append(lit) + else: + sym, counter = parseSymbol(token, prev, tokens[idx+1:]) + exprs.append(sym) + idx += counter + prev = token + return exprs @@ -1,4 +1,5 @@ from lexer import lex +from parser import parse def _get_debug(): return True @@ -13,10 +14,13 @@ def main(): continue try: lexed = lex(inp) - #lexed = lex(inp, []) if _get_debug(): acc = " ".join([f"{l}" for l in lexed]) print(f" - LEX: {acc}") + parsed = parse(lexed) + if _get_debug(): + acc = " ".join([f"{p}" for p in parsed]) + print(f" - PARSE: {acc}") idx += 1 except Exception as e: print(f"panic! {e}") |
