diff --git a/README.md b/README.md index ac3db28..22fa86a 100644 --- a/README.md +++ b/README.md @@ -75,15 +75,14 @@ Lamb treats each λ expression as a binary tree. Variable binding and reduction ## Todo (pre-release): - - Make command output accessible in prompt - Prettier colors - Prevent macro-chaining recursion - step-by-step reduction - Full-reduce option (expand all macros) - PyPi package - Cleanup warnings + - Preprocess method: bind, macros to free, etc - History queue - - `W` isn't fully expanded. Why?? ## Todo: diff --git a/lamb/node.py b/lamb/node.py index c78e953..752a5bf 100644 --- a/lamb/node.py +++ b/lamb/node.py @@ -244,6 +244,7 @@ class ExpandableEndNode(EndNode): class FreeVar(EndNode): def __init__(self, name: str, *, runner = None): + super().__init__() self.name = name self.runner = runner # type: ignore diff --git a/lamb/runner.py b/lamb/runner.py index 30e8f4b..81120b7 100644 --- a/lamb/runner.py +++ b/lamb/runner.py @@ -110,9 +110,18 @@ class Runner: def reduce(self, node: lamb.node.Node, *, status = {}) -> None: - # Show warnings warning_text = [] + # Reduction Counter. + # We also count macro (and church) expansions, + # and subtract those from the final count. + k = 0 + macro_expansions = 0 + + stop_reason = StopReason.MAX_EXCEEDED + start_time = time.time() + out_text = [] + if status["has_history"] and len(self.history) != 0: warning_text += [ ("class:code", "$"), @@ -121,32 +130,31 @@ class Runner: ("class:warn", "\n") ] + only_macro = isinstance(node, lamb.node.ExpandableEndNode) + if only_macro: + warning_text += [ + ("class:warn", "All macros will be expanded"), + ("class:warn", "\n") + ] + m, node = lamb.node.finalize_macros(node, force = True) + macro_expansions += m + + for i in status["free_variables"]: warning_text += [ - ("class:warn", "Macro "), + ("class:warn", "Name "), ("class:code", i), - ("class:warn", " will become a free variable.\n"), + ("class:warn", " is a free variable\n"), ] printf(FormattedText(warning_text), style = lamb.utils.style) - # Reduction Counter. - # We also count macro (and church) expansions, - # and subtract those from the final count. - i = 0 - macro_expansions = 0 - stop_reason = StopReason.MAX_EXCEEDED - start_time = time.time() - full_reduce = isinstance(node, lamb.node.ExpandableEndNode) - out_text = [] - - - while (self.reduction_limit is None) or (i < self.reduction_limit): + while (self.reduction_limit is None) or (k < self.reduction_limit): # Show reduction count - if (i >= self.iter_update) and (i % self.iter_update == 0): - print(f" Reducing... {i:,}", end = "\r") + if (k >= self.iter_update) and (k % self.iter_update == 0): + print(f" Reducing... {k:,}", end = "\r") try: red_type, node = lamb.node.reduce(node) @@ -161,17 +169,17 @@ class Runner: break # Count reductions - i += 1 + k += 1 if red_type == lamb.node.ReductionType.FUNCTION_APPLY: macro_expansions += 1 # Expand all remaining macros - m, node = lamb.node.finalize_macros(node, force = full_reduce) + m, node = lamb.node.finalize_macros(node, force = only_macro) macro_expansions += m - if i >= self.iter_update: + if k >= self.iter_update: # Clear reduction counter - print(" " * round(14 + math.log10(i)), end = "\r") + print(" " * round(14 + math.log10(k)), end = "\r") out_text += [ ("class:result_header", f"Runtime: "), @@ -184,15 +192,10 @@ class Runner: ("class:text", f"{macro_expansions:,}"), ("class:result_header", f"\nReductions: "), - ("class:text", f"{i:,}\t"), + ("class:text", f"{k:,}\t"), ("class:muted", f"(Limit: {self.reduction_limit:,})") ] - if full_reduce: - out_text += [ - ("class:warn", "\nAll macros have been expanded") - ] - if (stop_reason == StopReason.BETA_NORMAL or stop_reason == StopReason.LOOP_DETECTED): out_text += [ ("class:result_header", "\n\n => "),