Started conversion to Tree reduction
parent
044ec60a49
commit
c5df3fcbed
|
@ -20,6 +20,7 @@
|
||||||
- Smart alignment in all printouts
|
- Smart alignment in all printouts
|
||||||
- Full-reduce option
|
- Full-reduce option
|
||||||
- Set reduction limit command
|
- Set reduction limit command
|
||||||
|
- Runtime limit
|
||||||
|
|
||||||
## Mention in Docs
|
## Mention in Docs
|
||||||
- lambda functions only work with single-letter arguments
|
- 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
|
from pyparsing import exceptions as ppx
|
||||||
|
|
||||||
|
import lamb.parser
|
||||||
import lamb.runner as runner
|
import lamb.runner as runner
|
||||||
import lamb.tokens as tokens
|
import lamb.tokens as tokens
|
||||||
import lamb.utils as utils
|
import lamb.utils as utils
|
||||||
|
@ -32,6 +33,7 @@ def _(event):
|
||||||
event.current_buffer.insert_text("λ")
|
event.current_buffer.insert_text("λ")
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
r = runner.Runner(
|
r = runner.Runner(
|
||||||
prompt_session = PromptSession(
|
prompt_session = PromptSession(
|
||||||
style = utils.style,
|
style = utils.style,
|
||||||
|
@ -43,10 +45,178 @@ r = runner.Runner(
|
||||||
("class:prompt", "~~> ")
|
("class:prompt", "~~> ")
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
r.run_lines([
|
class Node:
|
||||||
"T = λab.a",
|
def __init__(self):
|
||||||
"F = λab.b",
|
# 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)",
|
"NOT = λa.(a F T)",
|
||||||
"AND = λab.(a F b)",
|
"AND = λab.(a F b)",
|
||||||
"OR = λab.(a T b)",
|
"OR = λab.(a T b)",
|
||||||
|
@ -59,44 +229,4 @@ r.run_lines([
|
||||||
"Z = λn.n (λa.F) T",
|
"Z = λn.n (λa.F) T",
|
||||||
"MULT = λnmf.n (m f)",
|
"MULT = λnmf.n (m f)",
|
||||||
"H = λp.((PAIR (p F)) (S (p 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_expr <<= (
|
||||||
self.pp_church ^
|
#self.pp_church ^
|
||||||
self.pp_lambda_fun ^
|
self.pp_lambda_fun ^
|
||||||
self.pp_name ^
|
self.pp_name ^
|
||||||
(self.lp + self.pp_expr + self.rp) ^
|
(self.lp + self.pp_expr + self.rp) ^
|
||||||
|
@ -60,31 +60,31 @@ class LambdaParser:
|
||||||
self.pp_all = (
|
self.pp_all = (
|
||||||
self.pp_expr ^
|
self.pp_expr ^
|
||||||
self.pp_macro_def ^
|
self.pp_macro_def ^
|
||||||
self.pp_command ^
|
#self.pp_command ^
|
||||||
self.pp_call
|
self.pp_call
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
action_command,
|
#action_command,
|
||||||
action_macro_def,
|
#action_macro_def,
|
||||||
action_church,
|
#action_church,
|
||||||
action_func,
|
action_func,
|
||||||
action_bound,
|
action_bound,
|
||||||
action_macro,
|
action_macro,
|
||||||
action_apply
|
action_call
|
||||||
):
|
):
|
||||||
|
|
||||||
self.make_parser()
|
self.make_parser()
|
||||||
|
|
||||||
self.pp_command.set_parse_action(action_command)
|
#self.pp_command.set_parse_action(action_command)
|
||||||
self.pp_macro_def.set_parse_action(action_macro_def)
|
#self.pp_macro_def.set_parse_action(action_macro_def)
|
||||||
self.pp_church.set_parse_action(action_church)
|
#self.pp_church.set_parse_action(action_church)
|
||||||
self.pp_lambda_fun.set_parse_action(action_func)
|
self.pp_lambda_fun.set_parse_action(action_func)
|
||||||
self.pp_macro.set_parse_action(action_macro)
|
self.pp_macro.set_parse_action(action_macro)
|
||||||
self.pp_bound.set_parse_action(action_bound)
|
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):
|
def parse_line(self, line: str):
|
||||||
return self.pp_all.parse_string(
|
return self.pp_all.parse_string(
|
||||||
|
|
Reference in New Issue