diff --git a/.vscode/settings.json b/.vscode/settings.json index 7cd6d80..16a556c 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "cSpell.words": [ "autochurch", - "clearmacros", + "delmac", "Endnodes", "freevar", "mdel", diff --git a/README.md b/README.md index 07493d1..6b432f7 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,11 @@ Lamb understands many commands. Prefix them with a `:` in the prompt. `:mdel [macro]` Delete a macro -`:clearmacros` Delete all macros +`:step [yes | no]` Enable or disable step-by-step reduction. Toggle if no argument is given. + +`:expand [yes | no]` Enable or disable full expansion. Toggle if no argument is given. If full expansion is enabled, ALL macros will be expanded when printing output. + +`:delmac` Delete all macros `:save [filename]` \ `:load [filename]` \ @@ -77,8 +81,8 @@ The lines in a file look exactly the same as regular entries in the prompt, but ## Todo (pre-release, in this order): + - History queue - Prevent macro-chaining recursion - - Full-reduce option (expand all macros) - Update screenshot - Update documentation - Write "how it works" @@ -89,10 +93,9 @@ The lines in a file look exactly the same as regular entries in the prompt, but - Cleanup warnings - Syntax highlight printouts - Truncate long expressions in warnings - - History queue + indexing + - History indexing - Show history command - Loop detection - - Optimization: reduction can be slow with large trees. - $\alpha$-equivalence check - Command-line options (load a file) - Unchurch command: make church numerals human-readable diff --git a/lamb/runner/commands.py b/lamb/runner/commands.py index 905a876..6a7efd6 100644 --- a/lamb/runner/commands.py +++ b/lamb/runner/commands.py @@ -61,7 +61,7 @@ def cmd_step(command, runner) -> None: if target: printf( HTML( - f"Enabled step-by-step reduction." + f"Enabled step-by-step reduction." ), style = lamb.utils.style ) @@ -69,12 +69,59 @@ def cmd_step(command, runner) -> None: else: printf( HTML( - f"Disabled step-by-step reduction." + f"Disabled step-by-step reduction." ), style = lamb.utils.style ) runner.step_reduction = False +@lamb_command( + command_name = "expand", + help_text = "Toggle full expansion" +) +def cmd_expand(command, runner) -> None: + if len(command.args) > 1: + printf( + HTML( + f"Command :{command.name} takes no more than one argument." + ), + style = lamb.utils.style + ) + return + + target = not runner.full_expansion + if len(command.args) == 1: + if command.args[0].lower() in ("y", "yes"): + target = True + elif command.args[0].lower() in ("n", "no"): + target = False + else: + printf( + HTML( + f"Usage: :expand [yes|no]" + ), + style = lamb.utils.style + ) + return + + + if target: + printf( + HTML( + f"Enabled complete expansion." + ), + style = lamb.utils.style + ) + runner.full_expansion = True + else: + printf( + HTML( + f"Disabled complete expansion." + ), + style = lamb.utils.style + ) + runner.full_expansion = False + @lamb_command( command_name = "save", @@ -96,7 +143,8 @@ def cmd_save(command, runner) -> None: message = FormattedText([ ("class:warn", "File exists. Overwrite? "), ("class:text", "[yes/no]: ") - ]) + ]), + style = lamb.utils.style ).lower() if confirm != "yes": @@ -221,12 +269,13 @@ def mdel(command, runner) -> None: @lamb_command( help_text = "Delete all macros" ) -def clearmacros(command, runner) -> None: +def delmac(command, runner) -> None: confirm = prompt( message = FormattedText([ ("class:warn", "Are you sure? "), ("class:text", "[yes/no]: ") - ]) + ]), + style = lamb.utils.style ).lower() if confirm != "yes": diff --git a/lamb/runner/runner.py b/lamb/runner/runner.py index 5fa2ce0..63ca1ac 100644 --- a/lamb/runner/runner.py +++ b/lamb/runner/runner.py @@ -63,6 +63,9 @@ class Runner: # If true, reduce step-by-step. self.step_reduction = False + # If true, expand ALL macros when printing output + self.full_expansion = False + def prompt(self): return self.prompt_session.prompt( message = self.prompt_message @@ -170,13 +173,19 @@ class Runner: ("class:warn", "Skipping to end."), ]), style = lamb.utils.style) + # Print a space between step messages if self.step_reduction: print("") + # Clear reduction counter if it was printed if k >= self.iter_update: - # Clear reduction counter if it was printed print(" " * round(14 + math.log10(k)), end = "\r") + # Expand fully if necessary + if self.full_expansion: + o, node = lamb.nodes.expand(node, force_all = True) + macro_expansions += o + if only_macro: out_text += [ ("class:ok", f"Displaying macro content") @@ -198,6 +207,11 @@ class Runner: ("class:muted", f"(Limit: {self.reduction_limit:,})") ] + if self.full_expansion: + out_text += [ + ("class:ok", "\nAll macros have been expanded") + ] + if ( stop_reason == StopReason.BETA_NORMAL or stop_reason == StopReason.LOOP_DETECTED or @@ -208,14 +222,16 @@ class Runner: ("class:text", str(node)), # type: ignore ] - self.history.append(lamb.nodes.expand(node, force_all = True)[1]) - printf( FormattedText(out_text), style = lamb.utils.style ) + # Save to history + # Do this at the end so we don't always fully expand. + self.history.append(lamb.nodes.expand(node, force_all = True)[1]) + def save_macro( self, macro: MacroDef,