Improved macro reduction
parent
01632f6ec3
commit
a4af47435a
|
@ -6,7 +6,6 @@
|
||||||
- Good command parsing (`:help`, `:save`, `:load`, `:macros`, `:clear` are a bare minimum)
|
- Good command parsing (`:help`, `:save`, `:load`, `:macros`, `:clear` are a bare minimum)
|
||||||
- Python files: installable, package list, etc
|
- Python files: installable, package list, etc
|
||||||
- $\alpha$-equivalence check
|
- $\alpha$-equivalence check
|
||||||
- Don't expand macros until you absolutely have to
|
|
||||||
- Versioning
|
- Versioning
|
||||||
- Clean up runner & printing
|
- Clean up runner & printing
|
||||||
- Count reductions
|
- Count reductions
|
||||||
|
|
34
tokens.py
34
tokens.py
|
@ -109,15 +109,36 @@ class macro(LambdaToken):
|
||||||
raise TypeError("Can only compare macro with macro")
|
raise TypeError("Can only compare macro with macro")
|
||||||
return self.name == other.name
|
return self.name == other.name
|
||||||
|
|
||||||
def reduce(self, macro_table = {}, *, auto_free_vars = True) -> ReductionStatus:
|
def reduce(
|
||||||
if self.name in macro_table:
|
self,
|
||||||
|
macro_table = {},
|
||||||
|
*,
|
||||||
|
# To keep output readable, we avoid expanding macros as often as possible.
|
||||||
|
# Macros are irreducible if force_substitute is false.
|
||||||
|
force_substitute = False,
|
||||||
|
|
||||||
|
# If this is false, error when macros aren't defined instead of
|
||||||
|
# invisibly making a free variable.
|
||||||
|
auto_free_vars = True
|
||||||
|
) -> ReductionStatus:
|
||||||
|
|
||||||
|
if (self.name in macro_table) and force_substitute:
|
||||||
|
if force_substitute: # Only expand macros if we NEED to
|
||||||
return ReductionStatus(
|
return ReductionStatus(
|
||||||
output = macro_table[self.name],
|
output = macro_table[self.name],
|
||||||
reduction_type = ReductionType.MACRO_EXPAND,
|
reduction_type = ReductionType.MACRO_EXPAND,
|
||||||
was_reduced = True
|
was_reduced = True
|
||||||
)
|
)
|
||||||
|
else: # Otherwise, do nothing.
|
||||||
|
return ReductionStatus(
|
||||||
|
output = self,
|
||||||
|
reduction_type = ReductionType.MACRO_EXPAND,
|
||||||
|
was_reduced = False
|
||||||
|
)
|
||||||
|
|
||||||
elif not auto_free_vars:
|
elif not auto_free_vars:
|
||||||
raise NameError(f"Name {self.name} is not defined!")
|
raise NameError(f"Name {self.name} is not defined!")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return ReductionStatus(
|
return ReductionStatus(
|
||||||
output = free_variable(self.name),
|
output = free_variable(self.name),
|
||||||
|
@ -449,8 +470,17 @@ class lambda_apply(LambdaToken):
|
||||||
|
|
||||||
# Otherwise, try to reduce self.fn.
|
# Otherwise, try to reduce self.fn.
|
||||||
# If that is impossible, try to reduce self.arg.
|
# If that is impossible, try to reduce self.arg.
|
||||||
|
else:
|
||||||
|
if isinstance(self.fn, macro):
|
||||||
|
# Macros must be reduced before we apply them as functions.
|
||||||
|
# This is the only place we force substitution.
|
||||||
|
r = self.fn.reduce(
|
||||||
|
macro_table,
|
||||||
|
force_substitute = True
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
r = self.fn.reduce(macro_table)
|
r = self.fn.reduce(macro_table)
|
||||||
|
|
||||||
# If a macro becomes a free variable,
|
# If a macro becomes a free variable,
|
||||||
# reduce twice.
|
# reduce twice.
|
||||||
if r.reduction_type == ReductionType.MACRO_TO_FREE:
|
if r.reduction_type == ReductionType.MACRO_TO_FREE:
|
||||||
|
|
Reference in New Issue