Started conversion to Tree reduction
parent
044ec60a49
commit
c5df3fcbed
|
@ -20,6 +20,7 @@
|
|||
- Smart alignment in all printouts
|
||||
- Full-reduce option
|
||||
- Set reduction limit command
|
||||
- Runtime limit
|
||||
|
||||
## Mention in Docs
|
||||
- lambda functions only work with single-letter arguments
|
||||
|
|
218
lamb/__main__.py
218
lamb/__main__.py
|
@ -8,6 +8,7 @@ from prompt_toolkit.lexers import Lexer
|
|||
|
||||
from pyparsing import exceptions as ppx
|
||||
|
||||
import lamb.parser
|
||||
import lamb.runner as runner
|
||||
import lamb.tokens as tokens
|
||||
import lamb.utils as utils
|
||||
|
@ -32,6 +33,7 @@ def _(event):
|
|||
event.current_buffer.insert_text("λ")
|
||||
|
||||
|
||||
"""
|
||||
r = runner.Runner(
|
||||
prompt_session = PromptSession(
|
||||
style = utils.style,
|
||||
|
@ -43,10 +45,178 @@ r = runner.Runner(
|
|||
("class:prompt", "~~> ")
|
||||
]),
|
||||
)
|
||||
"""
|
||||
|
||||
r.run_lines([
|
||||
"T = λab.a",
|
||||
"F = λab.b",
|
||||
class Node:
|
||||
def __init__(self):
|
||||
# The node this one is connected to.
|
||||
# None if this is the top node.
|
||||
self.parent: Node | None = None
|
||||
|
||||
# True if we're connected to the left side
|
||||
# of the parent, False otherwise.
|
||||
self.parent_left: bool | None = None
|
||||
|
||||
# Left and right nodes, None if empty
|
||||
self.left: Node | None = None
|
||||
self.right: Node | None = None
|
||||
|
||||
def set_parent(self, parent, is_left):
|
||||
self.parent = parent
|
||||
self.parent_left = is_left
|
||||
|
||||
def go_left(self):
|
||||
if self.left is None:
|
||||
raise Exception("Can't go left when left is None")
|
||||
return None, self.left
|
||||
|
||||
def go_right(self):
|
||||
if self.right is None:
|
||||
raise Exception("Can't go right when right is None")
|
||||
return None, self.right
|
||||
|
||||
def go_up(self):
|
||||
if self.parent is None:
|
||||
raise Exception("Can't go up when parent is None")
|
||||
return self.parent_left, self.parent
|
||||
|
||||
def to_node(result_pair) -> Node:
|
||||
return result_pair[0].from_parse(result_pair[1])
|
||||
|
||||
|
||||
class Macro(Node):
|
||||
@staticmethod
|
||||
def from_parse(results):
|
||||
return Macro(results[0])
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
def __repr__(self):
|
||||
return f"<macro {self.name}>"
|
||||
|
||||
class Func(Node):
|
||||
@staticmethod
|
||||
def from_parse(result):
|
||||
if len(result[0]) == 1:
|
||||
i = to_node(result[0][0])
|
||||
below = to_node(result[1])
|
||||
this = Func(i, below) # type: ignore
|
||||
|
||||
below.set_parent(this, True)
|
||||
return this
|
||||
else:
|
||||
i = to_node(result[0].pop(0))
|
||||
below = Func.from_parse(result)
|
||||
this = Func(i, below) # type: ignore
|
||||
|
||||
below.set_parent(this, True)
|
||||
return this
|
||||
|
||||
def __init__(self, input: Macro, output: Node) -> None:
|
||||
super().__init__()
|
||||
self.input = input
|
||||
self.left = output
|
||||
self.right = None
|
||||
|
||||
def __repr__(self):
|
||||
return f"<func {self.input!r} {self.left!r}>"
|
||||
|
||||
class Call(Node):
|
||||
@staticmethod
|
||||
def from_parse(results):
|
||||
if len(results) == 2:
|
||||
left = results[0]
|
||||
if not isinstance(left, Node):
|
||||
left = to_node(left)
|
||||
|
||||
right = to_node(results[1])
|
||||
this = Call(left, right)
|
||||
|
||||
left.set_parent(this, True)
|
||||
right.set_parent(this, False)
|
||||
return this
|
||||
else:
|
||||
left = results[0]
|
||||
if not isinstance(left, Node):
|
||||
left = to_node(left)
|
||||
|
||||
right = to_node(results[1])
|
||||
this = Call(left, right)
|
||||
|
||||
left.set_parent(this, True)
|
||||
right.set_parent(this, False)
|
||||
return Call.from_parse(
|
||||
[this] + results[2:]
|
||||
)
|
||||
|
||||
def __init__(self, fn: Node, arg: Node) -> None:
|
||||
super().__init__()
|
||||
self.left = fn
|
||||
self.right = arg
|
||||
|
||||
def __repr__(self):
|
||||
return f"<call {self.left!r} {self.right!r}>"
|
||||
|
||||
p = lamb.parser.LambdaParser(
|
||||
action_func = lambda x: (Func, x),
|
||||
action_bound = lambda x: (Macro, x),
|
||||
action_macro = lambda x: (Macro, x),
|
||||
action_call = lambda x: (Call, x)
|
||||
)
|
||||
|
||||
|
||||
def traverse(node: Node):
|
||||
ptr = node
|
||||
back_from_left = None
|
||||
|
||||
out = ""
|
||||
|
||||
while True:
|
||||
if isinstance(ptr, Macro):
|
||||
out += ptr.name
|
||||
back_from_left, ptr = ptr.go_up()
|
||||
if isinstance(ptr, Func):
|
||||
if back_from_left is None:
|
||||
if isinstance(ptr.parent, Func):
|
||||
out += ptr.input.name
|
||||
else:
|
||||
out += "λ" + ptr.input.name
|
||||
if not isinstance(ptr.left, Func):
|
||||
out += "."
|
||||
back_from_left, ptr = ptr.go_left()
|
||||
elif back_from_left is True:
|
||||
back_from_left, ptr = ptr.go_up()
|
||||
if isinstance(ptr, Call):
|
||||
if back_from_left is None:
|
||||
out += "("
|
||||
back_from_left, ptr = ptr.go_left()
|
||||
elif back_from_left is True:
|
||||
out += " "
|
||||
back_from_left, ptr = ptr.go_right()
|
||||
elif back_from_left is False:
|
||||
out += ")"
|
||||
back_from_left, ptr = ptr.go_up()
|
||||
|
||||
if ptr.parent is None:
|
||||
break
|
||||
return out
|
||||
|
||||
for l in [
|
||||
"λab.(a (NOT a b) b)",
|
||||
"λnmf.n (m f)",
|
||||
"λf.(λx. f(x x))(λx.f(x x))",
|
||||
]:
|
||||
i = p.parse_line(l)
|
||||
#print(i)
|
||||
n = to_node(i)
|
||||
#print(n)
|
||||
print(traverse(n))
|
||||
|
||||
"""
|
||||
"NOT = λa.(a F T)",
|
||||
"AND = λab.(a F b)",
|
||||
"OR = λab.(a T b)",
|
||||
|
@ -59,44 +229,4 @@ r.run_lines([
|
|||
"Z = λn.n (λa.F) T",
|
||||
"MULT = λnmf.n (m f)",
|
||||
"H = λp.((PAIR (p F)) (S (p F)))",
|
||||
"D = λn.n H (PAIR 0 0) T",
|
||||
"FAC = λyn.(Z n)(1)(MULT n (y (D n)))"
|
||||
])
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
i = r.prompt()
|
||||
|
||||
# Catch Ctrl-C and Ctrl-D
|
||||
except KeyboardInterrupt:
|
||||
printf("\n\nGoodbye.\n")
|
||||
break
|
||||
except EOFError:
|
||||
printf("\n\nGoodbye.\n")
|
||||
break
|
||||
|
||||
# Skip empty lines
|
||||
if i.strip() == "":
|
||||
continue
|
||||
|
||||
|
||||
# Try to run an input line.
|
||||
# Catch parse errors and point them out.
|
||||
try:
|
||||
x = r.run(i)
|
||||
except ppx.ParseException as e:
|
||||
l = len(to_plain_text(r.prompt_session.message))
|
||||
printf(FormattedText([
|
||||
("class:err", " "*(e.loc + l) + "^\n"),
|
||||
("class:err", f"Syntax error at char {e.loc}."),
|
||||
("class:text", "\n")
|
||||
]), style = utils.style)
|
||||
continue
|
||||
except tokens.ReductionError as e:
|
||||
printf(FormattedText([
|
||||
("class:err", f"{e.msg}\n")
|
||||
]), style = utils.style)
|
||||
continue
|
||||
|
||||
printf("")
|
||||
])"""
|
||||
|
|
|
@ -47,7 +47,7 @@ class LambdaParser:
|
|||
)
|
||||
|
||||
self.pp_expr <<= (
|
||||
self.pp_church ^
|
||||
#self.pp_church ^
|
||||
self.pp_lambda_fun ^
|
||||
self.pp_name ^
|
||||
(self.lp + self.pp_expr + self.rp) ^
|
||||
|
@ -60,31 +60,31 @@ class LambdaParser:
|
|||
self.pp_all = (
|
||||
self.pp_expr ^
|
||||
self.pp_macro_def ^
|
||||
self.pp_command ^
|
||||
#self.pp_command ^
|
||||
self.pp_call
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
action_command,
|
||||
action_macro_def,
|
||||
action_church,
|
||||
#action_command,
|
||||
#action_macro_def,
|
||||
#action_church,
|
||||
action_func,
|
||||
action_bound,
|
||||
action_macro,
|
||||
action_apply
|
||||
action_call
|
||||
):
|
||||
|
||||
self.make_parser()
|
||||
|
||||
self.pp_command.set_parse_action(action_command)
|
||||
self.pp_macro_def.set_parse_action(action_macro_def)
|
||||
self.pp_church.set_parse_action(action_church)
|
||||
#self.pp_command.set_parse_action(action_command)
|
||||
#self.pp_macro_def.set_parse_action(action_macro_def)
|
||||
#self.pp_church.set_parse_action(action_church)
|
||||
self.pp_lambda_fun.set_parse_action(action_func)
|
||||
self.pp_macro.set_parse_action(action_macro)
|
||||
self.pp_bound.set_parse_action(action_bound)
|
||||
self.pp_call.set_parse_action(action_apply)
|
||||
self.pp_call.set_parse_action(action_call)
|
||||
|
||||
def parse_line(self, line: str):
|
||||
return self.pp_all.parse_string(
|
||||
|
|
Reference in New Issue