Fixed parser, added macro printout
parent
ee744b5245
commit
8558c484c5
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
|
|
||||||
## Todo (pre-release):
|
## Todo (pre-release):
|
||||||
- Fix parser (call parentheses)
|
|
||||||
- Good command parsing (`:save`, `:load`, are a bare minimum)
|
- Good command parsing (`:save`, `:load`, are a bare minimum)
|
||||||
- Python files: installable, package list, etc
|
- Python files: installable, package list, etc
|
||||||
- $\alpha$-equivalence check
|
- $\alpha$-equivalence check
|
||||||
|
@ -18,6 +17,7 @@
|
||||||
- Warn when overwriting macro
|
- Warn when overwriting macro
|
||||||
- Syntax highlighting: parenthesis, bound variables, macros, etc
|
- Syntax highlighting: parenthesis, bound variables, macros, etc
|
||||||
- Pin header to top of screen
|
- Pin header to top of screen
|
||||||
|
- Parser is a bit slow. Maybe we can do better?
|
||||||
|
|
||||||
## Mention in Docs
|
## Mention in Docs
|
||||||
- lambda functions only work with single-letter arguments
|
- lambda functions only work with single-letter arguments
|
||||||
|
|
10
main.py
10
main.py
|
@ -43,7 +43,7 @@ r.run_lines([
|
||||||
"OR = λab.(a T b)",
|
"OR = λab.(a T b)",
|
||||||
"XOR = λab.(a (NOT a b) b)",
|
"XOR = λab.(a (NOT a b) b)",
|
||||||
"w = λx.(x x)",
|
"w = λx.(x x)",
|
||||||
"W = (w w)",
|
"W = w w",
|
||||||
"Y = λf.( (λx.(f (x x))) (λx.(f (x x))) )",
|
"Y = λf.( (λx.(f (x x))) (λx.(f (x x))) )",
|
||||||
"PAIR = λabi.( i a b )",
|
"PAIR = λabi.( i a b )",
|
||||||
"inc = λnfa.(f (n f a))",
|
"inc = λnfa.(f (n f a))",
|
||||||
|
@ -90,7 +90,13 @@ while True:
|
||||||
|
|
||||||
# If this line defined a macro, print nothing.
|
# If this line defined a macro, print nothing.
|
||||||
if isinstance(x, runner.MacroStatus):
|
if isinstance(x, runner.MacroStatus):
|
||||||
pass
|
printf(FormattedText([
|
||||||
|
("#FFFFFF", "Set "),
|
||||||
|
("#FF00FF", x.macro_label),
|
||||||
|
("#FFFFFF", " to "),
|
||||||
|
("#FFFFFF", str(x.macro_expr))
|
||||||
|
]))
|
||||||
|
|
||||||
|
|
||||||
if isinstance(x, runner.CommandStatus):
|
if isinstance(x, runner.CommandStatus):
|
||||||
printf(x.formatted_text)
|
printf(x.formatted_text)
|
||||||
|
|
66
parser.py
66
parser.py
|
@ -3,16 +3,6 @@ import tokens
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
class Parser:
|
class Parser:
|
||||||
"""
|
|
||||||
Macro_def must be on its own line.
|
|
||||||
macro_def :: var = expr
|
|
||||||
|
|
||||||
var :: word
|
|
||||||
lambda_fun :: var -> expr
|
|
||||||
call :: '(' (var | expr) ')' +
|
|
||||||
expr :: define | var | call | '(' expr ')'
|
|
||||||
"""
|
|
||||||
|
|
||||||
lp = pp.Suppress("(")
|
lp = pp.Suppress("(")
|
||||||
rp = pp.Suppress(")")
|
rp = pp.Suppress(")")
|
||||||
|
|
||||||
|
@ -24,6 +14,15 @@ class Parser:
|
||||||
pp_church = pp.Word(pp.nums)
|
pp_church = pp.Word(pp.nums)
|
||||||
pp_church.set_parse_action(utils.autochurch)
|
pp_church.set_parse_action(utils.autochurch)
|
||||||
|
|
||||||
|
# Function calls.
|
||||||
|
# `tokens.lambda_apply.from_parse` handles chained calls.
|
||||||
|
#
|
||||||
|
# <exp> <exp>
|
||||||
|
# <exp> <exp> <exp>
|
||||||
|
pp_call = pp.Forward()
|
||||||
|
pp_call <<= pp_expr[2, ...]
|
||||||
|
pp_call.set_parse_action(tokens.lambda_apply.from_parse)
|
||||||
|
|
||||||
# Function definitions.
|
# Function definitions.
|
||||||
# Right associative.
|
# Right associative.
|
||||||
#
|
#
|
||||||
|
@ -32,41 +31,44 @@ class Parser:
|
||||||
(pp.Suppress("λ") | pp.Suppress("\\")) +
|
(pp.Suppress("λ") | pp.Suppress("\\")) +
|
||||||
pp.Group(pp.Char(pp.alphas)[1, ...]) +
|
pp.Group(pp.Char(pp.alphas)[1, ...]) +
|
||||||
pp.Suppress(".") +
|
pp.Suppress(".") +
|
||||||
pp_expr
|
(pp_expr ^ pp_call)
|
||||||
)
|
)
|
||||||
pp_lambda_fun.set_parse_action(tokens.lambda_func.from_parse)
|
pp_lambda_fun.set_parse_action(tokens.lambda_func.from_parse)
|
||||||
|
|
||||||
# Assignment.
|
# Assignment.
|
||||||
# Can only be found at the start of a line.
|
# Can only be found at the start of a line.
|
||||||
#
|
#
|
||||||
# <var> = <exp>
|
# <name> = <exp>
|
||||||
pp_macro_def = pp.line_start() + pp_macro + pp.Suppress("=") + pp_expr
|
pp_macro_def = (
|
||||||
|
pp.line_start() +
|
||||||
|
pp_macro +
|
||||||
|
pp.Suppress("=") +
|
||||||
|
(pp_expr ^ pp_call)
|
||||||
|
)
|
||||||
pp_macro_def.set_parse_action(tokens.macro_expression.from_parse)
|
pp_macro_def.set_parse_action(tokens.macro_expression.from_parse)
|
||||||
|
|
||||||
# Function calls.
|
pp_expr <<= (
|
||||||
# `tokens.lambda_func.from_parse` handles chained calls.
|
pp_church ^
|
||||||
#
|
pp_lambda_fun ^
|
||||||
# <var>(<exp>)
|
pp_macro ^
|
||||||
# <var>(<exp>)(<exp>)(<exp>)
|
(lp + pp_expr + rp) ^
|
||||||
# (<exp>)(<exp>)
|
(lp + pp_call + rp)
|
||||||
# (<exp>)(<exp>)(<exp>)(<exp>)
|
)
|
||||||
pp_call = pp.Forward()
|
|
||||||
pp_call <<= pp_expr[2, ...]
|
|
||||||
pp_call.set_parse_action(tokens.lambda_apply.from_parse)
|
|
||||||
|
|
||||||
pp_expr <<= pp_lambda_fun ^ (lp + pp_expr + rp) ^ pp_macro ^ (lp + pp_call + rp) ^ pp_church
|
|
||||||
pp_all = pp_expr | pp_macro_def
|
|
||||||
|
|
||||||
pp_command = pp.Suppress(":") + pp.Word(pp.alphas + "_")
|
pp_command = pp.Suppress(":") + pp.Word(pp.alphas + "_")
|
||||||
pp_command.set_parse_action(tokens.command.from_parse)
|
pp_command.set_parse_action(tokens.command.from_parse)
|
||||||
|
|
||||||
|
|
||||||
|
pp_all = (
|
||||||
|
pp_expr ^
|
||||||
|
pp_macro_def ^
|
||||||
|
pp_command ^
|
||||||
|
pp_call
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_line(line):
|
def parse_line(line):
|
||||||
k = (
|
k = Parser.pp_all.parse_string(
|
||||||
Parser.pp_expr ^
|
|
||||||
Parser.pp_macro_def ^
|
|
||||||
Parser.pp_command ^ Parser.pp_call
|
|
||||||
).parse_string(
|
|
||||||
line,
|
line,
|
||||||
parse_all = True
|
parse_all = True
|
||||||
)[0]
|
)[0]
|
||||||
|
@ -75,4 +77,4 @@ class Parser:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def run_tests(lines):
|
def run_tests(lines):
|
||||||
return Parser.pp_macro_def.run_tests(lines)
|
return Parser.pp_all.run_tests(lines)
|
|
@ -77,7 +77,8 @@ class Runner:
|
||||||
|
|
||||||
return MacroStatus(
|
return MacroStatus(
|
||||||
was_rewritten = was_rewritten,
|
was_rewritten = was_rewritten,
|
||||||
macro_label = e.label
|
macro_label = e.label,
|
||||||
|
macro_expr = e.exp
|
||||||
)
|
)
|
||||||
|
|
||||||
# If this line is a command, do the command.
|
# If this line is a command, do the command.
|
||||||
|
|
|
@ -17,16 +17,19 @@ class MacroStatus(RunStatus):
|
||||||
Values:
|
Values:
|
||||||
`was_rewritten`: If true, an old macro was replaced.
|
`was_rewritten`: If true, an old macro was replaced.
|
||||||
`macro_label`: The name of the macro we just made.
|
`macro_label`: The name of the macro we just made.
|
||||||
|
`macro_expr`: The expr of the macro we just made.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
was_rewritten: bool,
|
was_rewritten: bool,
|
||||||
macro_label: str
|
macro_label: str,
|
||||||
|
macro_expr
|
||||||
):
|
):
|
||||||
self.was_rewritten = was_rewritten
|
self.was_rewritten = was_rewritten
|
||||||
self.macro_label = macro_label
|
self.macro_label = macro_label
|
||||||
|
self.macro_expr = macro_expr
|
||||||
|
|
||||||
|
|
||||||
class StopReason(enum.Enum):
|
class StopReason(enum.Enum):
|
||||||
|
|
Reference in New Issue