From bd13b10f761d6103fae3d1988cd15efdcb227b17 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 10 Nov 2022 09:08:58 -0800 Subject: [PATCH] Added subscript parsing --- README.md | 1 - lamb/nodes/functions.py | 7 +++++-- lamb/nodes/nodes.py | 7 ++++++- lamb/parser.py | 2 +- lamb/utils.py | 11 ++++++++--- 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index de7bd61..98e41c6 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,6 @@ The lines in a file look exactly the same as regular entries in the prompt, but ## Todo (pre-release, in this order): - - Export will break with :save, fix it. - Prevent macro-chaining recursion - Full-reduce option (expand all macros) - step-by-step reduction diff --git a/lamb/nodes/functions.py b/lamb/nodes/functions.py index 423bdb3..1f3236d 100644 --- a/lamb/nodes/functions.py +++ b/lamb/nodes/functions.py @@ -166,11 +166,14 @@ def prepare(root: lbn.Root, *, ban_macro_name = None) -> list: if (n.input.name in bound_variables): raise lbn.ReductionError(f"Bound variable name conflict: \"{n.input.name}\"") else: - bound_variables[n.input.name] = lbn.Bound(n.input.name) + bound_variables[n.input.name] = lbn.Bound( + lamb.utils.remove_sub(n.input.name), + macro_name = n.input.name + ) n.input = bound_variables[n.input.name] elif s == lbn.Direction.LEFT: - del bound_variables[n.input.name] + del bound_variables[n.input.macro_name] # type: ignore return warnings diff --git a/lamb/nodes/nodes.py b/lamb/nodes/nodes.py index 70f877e..e231e20 100644 --- a/lamb/nodes/nodes.py +++ b/lamb/nodes/nodes.py @@ -333,11 +333,16 @@ class History(ExpandableEndNode): bound_counter = 0 class Bound(EndNode): - def __init__(self, name: str, *, forced_id = None, runner = None): + def __init__(self, name: str, *, forced_id = None, runner = None, macro_name = None): self.name = name global bound_counter self.runner = runner # type: ignore + # The name of the macro this bound came from. + # Always equal to self.name, unless the macro + # this came from had a subscript. + self.macro_name: str | None = macro_name + if forced_id is None: self.identifier = bound_counter bound_counter += 1 diff --git a/lamb/parser.py b/lamb/parser.py index 0d32a81..1198eee 100755 --- a/lamb/parser.py +++ b/lamb/parser.py @@ -13,7 +13,7 @@ class LambdaParser: # We still create macro objects from them, they are turned into # bound variables after the expression is built. self.pp_macro = pp.Word(pp.alphas + "_") - self.pp_bound = pp.Char(pp.srange("[a-z]")) + self.pp_bound = pp.Regex("[a-z][₀₁₂₃₄₅₆₈₉]*") self.pp_name = self.pp_bound ^ self.pp_macro self.pp_church = pp.Word(pp.nums) self.pp_history = pp.Char("$") diff --git a/lamb/utils.py b/lamb/utils.py index 22a8a09..62617a0 100644 --- a/lamb/utils.py +++ b/lamb/utils.py @@ -5,6 +5,8 @@ from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit import print_formatted_text as printf from importlib.metadata import version +import re + style = Style.from_dict({ # type: ignore # Basic formatting @@ -108,6 +110,9 @@ def show_greeting(): "" ])), style = style) +def remove_sub(s: str): + return re.sub("[₀₁₂₃₄₅₆₈₉]*", "", s) + def base4(n: int): if n == 0: return [0] @@ -119,9 +124,9 @@ def base4(n: int): def subscript(num: int): - # unicode subscripts ₀₁₂₃ - # usually look different than - # the rest, so we'll use base 4. + # unicode subscripts ₀₁₂₃ and ₄₅₆₈₉ + # usually look different, + # so we'll use base 4. qb = base4(num) sub = {