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,