From 8558c484c54e989750a798c42535ca5a82586cf3 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 21 Oct 2022 19:55:15 -0700 Subject: [PATCH] Fixed parser, added macro printout --- README.md | 2 +- main.py | 10 ++++++-- parser.py | 66 +++++++++++++++++++++++++++------------------------- runner.py | 3 ++- runstatus.py | 5 +++- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 3659894..a2185fc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ ## Todo (pre-release): - - Fix parser (call parentheses) - Good command parsing (`:save`, `:load`, are a bare minimum) - Python files: installable, package list, etc - $\alpha$-equivalence check @@ -18,6 +17,7 @@ - Warn when overwriting macro - Syntax highlighting: parenthesis, bound variables, macros, etc - Pin header to top of screen + - Parser is a bit slow. Maybe we can do better? ## Mention in Docs - lambda functions only work with single-letter arguments diff --git a/main.py b/main.py index f5f4f05..45bf826 100755 --- a/main.py +++ b/main.py @@ -43,7 +43,7 @@ r.run_lines([ "OR = λab.(a T b)", "XOR = λab.(a (NOT a b) b)", "w = λx.(x x)", - "W = (w w)", + "W = w w", "Y = λf.( (λx.(f (x x))) (λx.(f (x x))) )", "PAIR = λabi.( i a b )", "inc = λnfa.(f (n f a))", @@ -90,7 +90,13 @@ while True: # If this line defined a macro, print nothing. if isinstance(x, runner.MacroStatus): - pass + printf(FormattedText([ + ("#FFFFFF", "Set "), + ("#FF00FF", x.macro_label), + ("#FFFFFF", " to "), + ("#FFFFFF", str(x.macro_expr)) + ])) + if isinstance(x, runner.CommandStatus): printf(x.formatted_text) diff --git a/parser.py b/parser.py index 919edbe..49c90af 100755 --- a/parser.py +++ b/parser.py @@ -3,16 +3,6 @@ import tokens import utils class Parser: - """ - Macro_def must be on its own line. - macro_def :: var = expr - - var :: word - lambda_fun :: var -> expr - call :: '(' (var | expr) ')' + - expr :: define | var | call | '(' expr ')' - """ - lp = pp.Suppress("(") rp = pp.Suppress(")") @@ -24,6 +14,15 @@ class Parser: pp_church = pp.Word(pp.nums) pp_church.set_parse_action(utils.autochurch) + # Function calls. + # `tokens.lambda_apply.from_parse` handles chained calls. + # + # + # + pp_call = pp.Forward() + pp_call <<= pp_expr[2, ...] + pp_call.set_parse_action(tokens.lambda_apply.from_parse) + # Function definitions. # Right associative. # @@ -32,41 +31,44 @@ class Parser: (pp.Suppress("λ") | pp.Suppress("\\")) + pp.Group(pp.Char(pp.alphas)[1, ...]) + pp.Suppress(".") + - pp_expr + (pp_expr ^ pp_call) ) pp_lambda_fun.set_parse_action(tokens.lambda_func.from_parse) # Assignment. # Can only be found at the start of a line. # - # = - pp_macro_def = pp.line_start() + pp_macro + pp.Suppress("=") + pp_expr + # = + pp_macro_def = ( + pp.line_start() + + pp_macro + + pp.Suppress("=") + + (pp_expr ^ pp_call) + ) pp_macro_def.set_parse_action(tokens.macro_expression.from_parse) - # Function calls. - # `tokens.lambda_func.from_parse` handles chained calls. - # - # () - # ()()() - # ()() - # ()()()() - pp_call = pp.Forward() - pp_call <<= pp_expr[2, ...] - pp_call.set_parse_action(tokens.lambda_apply.from_parse) - - pp_expr <<= pp_lambda_fun ^ (lp + pp_expr + rp) ^ pp_macro ^ (lp + pp_call + rp) ^ pp_church - pp_all = pp_expr | pp_macro_def + pp_expr <<= ( + pp_church ^ + pp_lambda_fun ^ + pp_macro ^ + (lp + pp_expr + rp) ^ + (lp + pp_call + rp) + ) pp_command = pp.Suppress(":") + pp.Word(pp.alphas + "_") pp_command.set_parse_action(tokens.command.from_parse) + + pp_all = ( + pp_expr ^ + pp_macro_def ^ + pp_command ^ + pp_call + ) + @staticmethod def parse_line(line): - k = ( - Parser.pp_expr ^ - Parser.pp_macro_def ^ - Parser.pp_command ^ Parser.pp_call - ).parse_string( + k = Parser.pp_all.parse_string( line, parse_all = True )[0] @@ -75,4 +77,4 @@ class Parser: @staticmethod def run_tests(lines): - return Parser.pp_macro_def.run_tests(lines) \ No newline at end of file + return Parser.pp_all.run_tests(lines) \ No newline at end of file diff --git a/runner.py b/runner.py index e11dfb4..41cc762 100644 --- a/runner.py +++ b/runner.py @@ -77,7 +77,8 @@ class Runner: return MacroStatus( was_rewritten = was_rewritten, - macro_label = e.label + macro_label = e.label, + macro_expr = e.exp ) # If this line is a command, do the command. diff --git a/runstatus.py b/runstatus.py index 2a43af5..504dd3c 100644 --- a/runstatus.py +++ b/runstatus.py @@ -17,16 +17,19 @@ class MacroStatus(RunStatus): Values: `was_rewritten`: If true, an old macro was replaced. `macro_label`: The name of the macro we just made. + `macro_expr`: The expr of the macro we just made. """ def __init__( self, *, was_rewritten: bool, - macro_label: str + macro_label: str, + macro_expr ): self.was_rewritten = was_rewritten self.macro_label = macro_label + self.macro_expr = macro_expr class StopReason(enum.Enum):