aboutsummaryrefslogtreecommitdiff
path: root/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'parser.py')
-rw-r--r--parser.py176
1 files changed, 101 insertions, 75 deletions
diff --git a/parser.py b/parser.py
index 98a4712..f331cfe 100644
--- a/parser.py
+++ b/parser.py
@@ -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