diff options
| author | mryouse | 2022-05-13 02:35:25 +0000 |
|---|---|---|
| committer | mryouse | 2022-05-13 02:35:25 +0000 |
| commit | 3d23b45a0ab381f34a2dae327e22cfa862af46ea (patch) | |
| tree | 104bd1949d60947058b1208169b0372092b0f14c | |
| parent | e18bdec21683adfb2658359568a54a2f3f21d703 (diff) | |
lists? not sure if they fully work, but somewhat
| -rw-r--r-- | lexer.py | 28 | ||||
| -rw-r--r-- | parser.py | 36 | ||||
| -rw-r--r-- | runner.py | 2 | ||||
| -rw-r--r-- | std.py | 24 | ||||
| -rw-r--r-- | tokens.py | 20 |
5 files changed, 101 insertions, 9 deletions
@@ -5,6 +5,8 @@ DOUBLE_QUOTE = '"' BACKSLASH = "\\" OPEN_PAREN = "(" CLOSE_PAREN = ")" +OPEN_BRACE = "[" +CLOSE_BRACE = "]" DIGITS = "0123456789" LETTERS = "abcdefghijklmnopqrstuvwxyz" PUNCTUATION = "-_!*$@%^&=+/?<>~" @@ -48,7 +50,7 @@ def lex_bool(inp): else: raise Exception("invalid boolean") - if peek(inp[len(str(token)):]) not in (None, " ", CLOSE_PAREN): + if peek(inp[len(str(token)):]) not in (None, " ", CLOSE_PAREN, CLOSE_BRACE): raise Exception("invalid boolean") #return token, inp[len(str(token)):] @@ -58,7 +60,7 @@ def lex_bool(inp): def lex_number(inp): token = "" for idx, c in enumerate(inp): - if c in (" ", CLOSE_PAREN): + if c in (" ", CLOSE_PAREN, CLOSE_BRACE): if "." in token: #return float(token), inp[idx:] return NebFloat(float(token)), inp[idx:] @@ -96,14 +98,13 @@ def lex_number(inp): def lex_symbol(inp): token = "" for idx, c in enumerate(inp): - if c in (CLOSE_PAREN, " "): + if c in (CLOSE_PAREN, CLOSE_BRACE, " "): return NebSymbol(token), inp[idx:] elif c in SYMBOL_VALS: token += c else: raise Exception("improper symbol") return NebSymbol(token), "" - def peek(inp): if len(inp) == 0: @@ -123,6 +124,13 @@ def lex(inp, tokens): elif nxt == CLOSE_PAREN: tokens.append(NebClose()) return lex(inp[1:], tokens) + # braces + elif nxt == OPEN_BRACE: + tokens.append(NebListStart()) + return lex(inp[1:], tokens) + elif nxt == CLOSE_BRACE: + tokens.append(NebListEnd()) + return lex(inp[1:], tokens) # numbers elif nxt in list(DIGITS) or nxt in ("+", "-", "."): # + and - are symbols, too @@ -130,7 +138,8 @@ def lex(inp, tokens): after = peek(inp[1:]) if after not in DIGITS: # parse a symbol token, remainder = lex_symbol(inp) - if peek(remainder) not in (None, CLOSE_PAREN, " "): + if peek(remainder) not in (None, CLOSE_PAREN, CLOSE_BRACE, " "): + print(f"{peek(remainder)}") raise Exception("spaces required between tokens") tokens.append(token) return lex(remainder, tokens) @@ -141,21 +150,24 @@ def lex(inp, tokens): elif nxt == DOUBLE_QUOTE: token, remainder = lex_string(inp[1:]) #print(f"received [{token}] [{remainder}]") - if peek(remainder) not in (None, CLOSE_PAREN, " "): + if peek(remainder) not in (None, CLOSE_PAREN, " ", CLOSE_BRACE): + print(f"{peek(remainder)}") raise Exception("spaces required between tokens") tokens.append(token) return lex(remainder, tokens) # bool elif nxt == "#": token, remainder = lex_bool(inp[1:]) - if peek(remainder) not in (None, CLOSE_PAREN, " "): + if peek(remainder) not in (None, CLOSE_PAREN, " ", CLOSE_BRACE): + print(f"{peek(remainder)}") raise Exception("spaces required between tokens") tokens.append(token) return lex(remainder, tokens) # symbols elif nxt in SYMBOL_VALS: token, remainder = lex_symbol(inp) - if peek(remainder) not in (None, CLOSE_PAREN, " "): + if peek(remainder) not in (None, CLOSE_PAREN, " ", CLOSE_BRACE): + print(f"{peek(remainder)}") raise Exception("spaces required between tokens") tokens.append(token) return lex(remainder, tokens) @@ -12,6 +12,7 @@ def parse_expression(tkns): 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 @@ -22,15 +23,46 @@ def parse_expression(tkns): symbol = t elif isinstance(t, NebClose): return NebExpression(symbol, args), tkns[idx + 1:], idx + 1 + # nested expressions elif isinstance(t, NebOpen): expr, remainder, add_idx = parse_expression(tkns[idx + 1:]) args.append(expr) + + 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) + else: args.append(t) raise Exception("couldn't parse expression!") +def parse_list(tkns): + items = [] + add_idx = 0 + for idx, t in enumerate(tkns): + if add_idx > 0: + add_idx -= 1 + continue + + 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) + + raise Exception("couldn't parse list!") + def parse(tkns, parsed): nxt = peek(tkns) if nxt is None: @@ -39,6 +71,10 @@ def parse(tkns, parsed): 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) @@ -11,7 +11,7 @@ def evaluate(items, pop): nxt = peek(items) if nxt is None: return pop - elif isinstance(nxt, NebLiteral): + elif isinstance(nxt, NebLiteral) or isinstance(nxt, NebList): return evaluate(items[1:], nxt) elif isinstance(nxt, NebSymbol): if not nxt.name in STD: @@ -1,6 +1,7 @@ from tokens import * import sys from collections import namedtuple +import subprocess FuncImpl = namedtuple("FuncImpl", ("func", "impl")) @@ -22,6 +23,16 @@ def std_print(arg): #return [] # TODO this should return empty list return NebBool(True) +def std_print_all(arg): + for idx, item in enumerate(arg.items): + if isinstance(item, NebExpression): + arg.items[idx] = evaluate_expression(item) + elif not isinstance(item, NebString): + raise exception("print-all needs all strings!") + for x in arg.items: + std_print(x) + return NebBool(True) + def std_debug_on(): global DEBUG DEBUG = True @@ -103,6 +114,12 @@ def std_is_bool(arg): else: return NebBool(False) +# shell +def std_shell(arg): + assert isinstance(arg, NebString) + subprocess.run(arg.value) + return NebBool(True) + def evaluate_expression(expr): if not expr.symbol.name in STD: raise Exception(f"no such symbol: {expr.symbol.name}") @@ -135,6 +152,9 @@ def build_std(): print_string = FuncImpl(NebFunction("print", [NebString], NebString), std_print) STD["print"] = [print_string] + print_all = FuncImpl(NebFunction("print-all", [NebList], NebBool), std_print_all) + STD["print-all"] = [print_all] + exit_ = FuncImpl(NebFunction("exit", [], NebBool), std_exit) exit_int = FuncImpl(NebFunction("exit", [NebInt], NebBool), std_exit) STD["exit"] = [exit_, exit_int] @@ -175,4 +195,8 @@ def build_std(): is_bool = FuncImpl(NebFunction("string?", [NebAny], NebBool), std_is_bool) STD["bool?"] = [is_bool] + # shell + shell_string = FuncImpl(NebFunction("$", [NebString], NebBool), std_shell) + STD["$"] = [shell_string] + build_std() @@ -14,6 +14,7 @@ class NebType(Enum): BOOL = auto() EXPR = auto() SYMBOL = auto() + LIST = auto() def __str__(self): return self.name.lower() @@ -57,6 +58,14 @@ class NebClose(NebSeparator): def __str__(self): return ")" +class NebListStart(NebSeparator): + def __str__(self): + return "[" + +class NebListEnd(NebSeparator): + def __str__(self): + return "]" + class NebSymbol(NebBaseType): def __init__(self, name): @@ -119,3 +128,14 @@ class NebFloat(NebNumber): def __init__(self, value): super().__init__("float", NebType.FLOAT, value) +class NebList(NebAny): + def __init__(self, items): + super().__init__("list", NebType.LIST) + self.items = items + + def __str__(self): + out = "[ " + for item in self.items: + out += f"{item} " + return f"{out}]" + |
