Compare commits
4 Commits
a7078f9a77
...
fa02c2aa5b
Author | SHA1 | Date | |
---|---|---|---|
fa02c2aa5b | |||
1bbca094dd | |||
0ef0e8e585 | |||
d11c9a5a7e |
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -2,7 +2,9 @@
|
|||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"autochurch",
|
"autochurch",
|
||||||
"freevar",
|
"freevar",
|
||||||
|
"mdel",
|
||||||
"onefile",
|
"onefile",
|
||||||
|
"Packrat",
|
||||||
"pyparsing",
|
"pyparsing",
|
||||||
"runstatus",
|
"runstatus",
|
||||||
"subvar"
|
"subvar"
|
||||||
|
@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
|
|
||||||
## Todo (pre-release):
|
## Todo (pre-release):
|
||||||
- Good command parsing (`:save`, `:load`, are a bare minimum)
|
|
||||||
- $\alpha$-equivalence check
|
- $\alpha$-equivalence check
|
||||||
- Prettyprint functions (combine args, rename bound variables)
|
- Prettyprint functions (combine args, rename bound variables)
|
||||||
- Write a nice README
|
- Write a nice README
|
||||||
- Delete macros
|
|
||||||
- Handle or avoid recursion errors
|
- Handle or avoid recursion errors
|
||||||
|
- Fix colors
|
||||||
|
|
||||||
## Todo:
|
## Todo:
|
||||||
- live syntax check
|
- live syntax check
|
||||||
@ -17,8 +16,8 @@
|
|||||||
- 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?
|
- PyPi package
|
||||||
- pypi package
|
- Smart alignment in all printouts
|
||||||
|
|
||||||
## Mention in Docs
|
## Mention in Docs
|
||||||
- lambda functions only work with single-letter arguments
|
- lambda functions only work with single-letter arguments
|
||||||
|
@ -4,34 +4,46 @@ from prompt_toolkit import print_formatted_text as printf
|
|||||||
from prompt_toolkit.formatted_text import FormattedText
|
from prompt_toolkit.formatted_text import FormattedText
|
||||||
from prompt_toolkit.formatted_text import to_plain_text
|
from prompt_toolkit.formatted_text import to_plain_text
|
||||||
from prompt_toolkit.key_binding import KeyBindings
|
from prompt_toolkit.key_binding import KeyBindings
|
||||||
|
from prompt_toolkit.lexers import Lexer
|
||||||
|
|
||||||
from pyparsing import exceptions as ppx
|
from pyparsing import exceptions as ppx
|
||||||
|
|
||||||
from lamb.parser import Parser
|
|
||||||
import lamb.runner as runner
|
import lamb.runner as runner
|
||||||
import lamb.runstatus as rs
|
import lamb.runstatus as rs
|
||||||
import lamb.tokens as tokens
|
import lamb.tokens as tokens
|
||||||
import lamb.utils as utils
|
import lamb.utils as utils
|
||||||
|
|
||||||
|
|
||||||
# Replace "\" with a pretty "λ" in the prompt
|
# Simple lexer for highlighting.
|
||||||
bindings = KeyBindings()
|
# Improve this later.
|
||||||
@bindings.add("\\")
|
class LambdaLexer(Lexer):
|
||||||
def _(event):
|
def lex_document(self, document):
|
||||||
event.current_buffer.insert_text("λ")
|
def inner(line_no):
|
||||||
|
return [("class:text", str(document.lines[line_no]))]
|
||||||
session = PromptSession(
|
return inner
|
||||||
message = FormattedText([
|
|
||||||
("#00FFFF", "~~> ")
|
|
||||||
]),
|
|
||||||
key_bindings = bindings
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
utils.show_greeting()
|
utils.show_greeting()
|
||||||
|
|
||||||
|
|
||||||
r = runner.Runner()
|
# Replace "\" with pretty "λ"s
|
||||||
|
bindings = KeyBindings()
|
||||||
|
@bindings.add("\\")
|
||||||
|
def _(event):
|
||||||
|
event.current_buffer.insert_text("λ")
|
||||||
|
|
||||||
|
|
||||||
|
r = runner.Runner(
|
||||||
|
prompt_session = PromptSession(
|
||||||
|
style = utils.style,
|
||||||
|
lexer = LambdaLexer(),
|
||||||
|
key_bindings = bindings
|
||||||
|
),
|
||||||
|
|
||||||
|
prompt_message = FormattedText([
|
||||||
|
("class:prompt", "~~> ")
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
r.run_lines([
|
r.run_lines([
|
||||||
"T = λab.a",
|
"T = λab.a",
|
||||||
@ -52,7 +64,7 @@ r.run_lines([
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
i = session.prompt()
|
i = r.prompt()
|
||||||
|
|
||||||
# Catch Ctrl-C and Ctrl-D
|
# Catch Ctrl-C and Ctrl-D
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
@ -72,46 +84,44 @@ while True:
|
|||||||
try:
|
try:
|
||||||
x = r.run(i)
|
x = r.run(i)
|
||||||
except ppx.ParseException as e:
|
except ppx.ParseException as e:
|
||||||
l = len(to_plain_text(session.message))
|
l = len(to_plain_text(r.prompt_session.message))
|
||||||
printf(FormattedText([
|
printf(FormattedText([
|
||||||
("#FF0000", " "*(e.loc + l) + "^\n"),
|
("class:err", " "*(e.loc + l) + "^\n"),
|
||||||
("#FF0000", f"Syntax error at char {e.loc}."),
|
("class:err", f"Syntax error at char {e.loc}."),
|
||||||
("#FFFFFF", "\n")
|
("class:text", "\n")
|
||||||
]))
|
]))
|
||||||
continue
|
continue
|
||||||
except tokens.ReductionError as e:
|
except tokens.ReductionError as e:
|
||||||
printf(FormattedText([
|
printf(FormattedText([
|
||||||
("#FF0000", f"{e.msg}"),
|
("class:err", f"{e.msg}\n")
|
||||||
("#FFFFFF", "\n")
|
]), style = utils.style)
|
||||||
]))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If this line defined a macro, print nothing.
|
# If this line defined a macro, print nothing.
|
||||||
if isinstance(x, rs.MacroStatus):
|
if isinstance(x, rs.MacroStatus):
|
||||||
printf(FormattedText([
|
printf(FormattedText([
|
||||||
("#FFFFFF", "Set "),
|
("class:text", "Set "),
|
||||||
("#FF00FF", x.macro_label),
|
("class:syn_macro", x.macro_label),
|
||||||
("#FFFFFF", " to "),
|
("class:text", " to "),
|
||||||
("#FFFFFF", str(x.macro_expr))
|
("class:text", str(x.macro_expr))
|
||||||
]))
|
]), style = utils.style)
|
||||||
|
|
||||||
|
|
||||||
if isinstance(x, rs.CommandStatus):
|
if isinstance(x, rs.CommandStatus):
|
||||||
printf(x.formatted_text)
|
pass
|
||||||
|
|
||||||
# If this line was an expression, print reduction status
|
# If this line was an expression, print reduction status
|
||||||
elif isinstance(x, rs.ReduceStatus):
|
elif isinstance(x, rs.ReduceStatus):
|
||||||
printf(FormattedText([
|
printf(FormattedText([
|
||||||
|
("class:result_header", f"\nExit reason: "),
|
||||||
("#00FF00 bold", f"\nExit reason: "),
|
|
||||||
x.stop_reason.value,
|
x.stop_reason.value,
|
||||||
|
|
||||||
("#00FF00 bold", f"\nReduction count: "),
|
("class:result_header", f"\nReduction count: "),
|
||||||
("#FFFFFF", str(x.reduction_count)),
|
("class:text", str(x.reduction_count)),
|
||||||
|
|
||||||
|
|
||||||
("#00FF00 bold", "\n\n => "),
|
("class:result_header", "\n\n => "),
|
||||||
("#FFFFFF", str(x.result)),
|
("class:text", str(x.result)),
|
||||||
]))
|
]), style = utils.style)
|
||||||
|
|
||||||
printf("")
|
printf("")
|
||||||
|
231
lamb/commands.py
231
lamb/commands.py
@ -1,8 +1,12 @@
|
|||||||
from prompt_toolkit.formatted_text import FormattedText
|
from prompt_toolkit.formatted_text import FormattedText
|
||||||
from prompt_toolkit.formatted_text import HTML
|
from prompt_toolkit.formatted_text import HTML
|
||||||
|
from prompt_toolkit import print_formatted_text as printf
|
||||||
from prompt_toolkit.shortcuts import clear as clear_screen
|
from prompt_toolkit.shortcuts import clear as clear_screen
|
||||||
|
|
||||||
from lamb.runstatus import CommandStatus
|
import os.path
|
||||||
|
|
||||||
|
from pyparsing import exceptions as ppx
|
||||||
|
import lamb.runstatus as rs
|
||||||
import lamb.utils as utils
|
import lamb.utils as utils
|
||||||
|
|
||||||
|
|
||||||
@ -16,100 +20,181 @@ def lamb_command(*, help_text: str):
|
|||||||
help_texts[func.__name__] = help_text
|
help_texts[func.__name__] = help_text
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
def run(command, runner):
|
def run(command, runner) -> None:
|
||||||
return commands[command.name](command, runner)
|
if command.name not in commands:
|
||||||
|
printf(
|
||||||
|
FormattedText([
|
||||||
|
("class:warn", f"Unknown command \"{command.name}\"")
|
||||||
|
]),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
commands[command.name](command, runner)
|
||||||
|
|
||||||
|
|
||||||
|
@lamb_command(help_text = "Save macros to a file")
|
||||||
|
def save(command, runner) -> None:
|
||||||
|
if len(command.args) != 1:
|
||||||
|
printf(
|
||||||
|
HTML(
|
||||||
|
"<err>Command <cmd_code>:save</cmd_code> takes exactly one argument.</err>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
target = command.args[0]
|
||||||
|
if os.path.exists(target):
|
||||||
|
confirm = runner.prompt_session.prompt(
|
||||||
|
message = FormattedText([
|
||||||
|
("class:warn", "File exists. Overwrite? "),
|
||||||
|
("class:text", "[yes/no]: ")
|
||||||
|
])
|
||||||
|
).lower()
|
||||||
|
|
||||||
|
if confirm != "yes":
|
||||||
|
printf(
|
||||||
|
HTML(
|
||||||
|
"<err>Cancelled.</err>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(target, "w") as f:
|
||||||
|
f.write("\n".join(
|
||||||
|
[f"{n} = {e}" for n, e in runner.macro_table.items()]
|
||||||
|
))
|
||||||
|
|
||||||
|
printf(
|
||||||
|
HTML(
|
||||||
|
f"Wrote {len(runner.macro_table)} macros to <cmd_code>{target}</cmd_code>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@lamb_command(help_text = "Load macros from a file")
|
||||||
|
def load(command, runner):
|
||||||
|
if len(command.args) != 1:
|
||||||
|
printf(
|
||||||
|
HTML(
|
||||||
|
"<err>Command <cmd_code>:load</cmd_code> takes exactly one argument.</err>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
target = command.args[0]
|
||||||
|
if not os.path.exists(target):
|
||||||
|
printf(
|
||||||
|
HTML(
|
||||||
|
f"<err>File {target} doesn't exist.</err>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(target, "r") as f:
|
||||||
|
lines = [x.strip() for x in f.readlines()]
|
||||||
|
|
||||||
|
for i in range(len(lines)):
|
||||||
|
l = lines[i]
|
||||||
|
try:
|
||||||
|
x = runner.run(l, macro_only = True)
|
||||||
|
except ppx.ParseException as e:
|
||||||
|
printf(
|
||||||
|
FormattedText([
|
||||||
|
("class:warn", f"Syntax error on line {i+1:02}: "),
|
||||||
|
("class:cmd_code", l[:e.loc]),
|
||||||
|
("class:err", l[e.loc]),
|
||||||
|
("class:cmd_code", l[e.loc+1:])
|
||||||
|
]),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
except rs.NotAMacro:
|
||||||
|
printf(
|
||||||
|
FormattedText([
|
||||||
|
("class:warn", f"Skipping line {i+1:02}: "),
|
||||||
|
("class:cmd_code", l),
|
||||||
|
("class:warn", f" is not a macro definition.")
|
||||||
|
]),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
printf(
|
||||||
|
FormattedText([
|
||||||
|
("class:ok", f"Loaded {x.macro_label}: "),
|
||||||
|
("class:cmd_code", str(x.macro_expr))
|
||||||
|
]),
|
||||||
|
style = utils.style
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@lamb_command(help_text = "Delete a macro")
|
@lamb_command(help_text = "Delete a macro")
|
||||||
def mdel(command, runner):
|
def mdel(command, runner) -> None:
|
||||||
if len(command.args) != 1:
|
if len(command.args) != 1:
|
||||||
return CommandStatus(
|
printf(
|
||||||
formatted_text = HTML(
|
HTML(
|
||||||
"<red>Command <grey>:mdel</grey> takes exactly one argument.</red>"
|
"<err>Command <cmd_code>:mdel</cmd_code> takes exactly one argument.</err>"
|
||||||
)
|
),
|
||||||
|
style = utils.style
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
target = command.args[0]
|
target = command.args[0]
|
||||||
if target not in runner.macro_table:
|
if target not in runner.macro_table:
|
||||||
return CommandStatus(
|
printf(
|
||||||
formatted_text = HTML(
|
HTML(
|
||||||
f"<red>Macro \"{target}\" is not defined</red>"
|
f"<warn>Macro \"{target}\" is not defined</warn>"
|
||||||
)
|
),
|
||||||
|
style = utils.style
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
del runner.macro_table[target]
|
del runner.macro_table[target]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@lamb_command(help_text = "Show macros")
|
@lamb_command(help_text = "Show macros")
|
||||||
def macros(command, runner):
|
def macros(command, runner) -> None:
|
||||||
return CommandStatus(
|
printf(FormattedText([
|
||||||
formatted_text = FormattedText([
|
("class:cmd_h", "\nDefined Macros:\n"),
|
||||||
("#FF6600 bold", "\nDefined Macros:\n"),
|
|
||||||
] +
|
] +
|
||||||
[
|
[
|
||||||
("#FFFFFF", f"\t{name} \t {exp}\n")
|
("class:cmd_text", f"\t{name} \t {exp}\n")
|
||||||
for name, exp in runner.macro_table.items()
|
for name, exp in runner.macro_table.items()
|
||||||
]
|
]),
|
||||||
)
|
style = utils.style
|
||||||
)
|
)
|
||||||
|
|
||||||
@lamb_command(help_text = "Clear the screen")
|
@lamb_command(help_text = "Clear the screen")
|
||||||
def clear(command, runner):
|
def clear(command, runner) -> None:
|
||||||
clear_screen()
|
clear_screen()
|
||||||
utils.show_greeting()
|
utils.show_greeting()
|
||||||
|
|
||||||
|
|
||||||
@lamb_command(help_text = "Print this help")
|
@lamb_command(help_text = "Print this help")
|
||||||
def help(command, runner):
|
def help(command, runner) -> None:
|
||||||
return CommandStatus(
|
printf(
|
||||||
formatted_text = FormattedText([
|
HTML(
|
||||||
("#FF6600 bold", "\nUsage:\n"),
|
"\n<cmd_text>" +
|
||||||
(
|
"<cmd_h>Usage:</cmd_h>" +
|
||||||
"#FFFFFF",
|
"\n" +
|
||||||
"\tWrite lambda expressions using your "
|
"\tWrite lambda expressions using your <cmd_key>\\</cmd_key> key." +
|
||||||
),
|
"\n" +
|
||||||
(
|
"\tMacros can be defined using <cmd_key>=</cmd_key>, as in <cmd_code>T = λab.a</cmd_code>" +
|
||||||
"#00FF00",
|
"\n" +
|
||||||
"\\"
|
"\tRun commands using <cmd_key>:</cmd_key>, for example <cmd_code>:help</cmd_code>" +
|
||||||
),
|
"\n\n" +
|
||||||
(
|
"<cmd_h>Commands:</cmd_h>"+
|
||||||
"#FFFFFF",
|
"\n" +
|
||||||
" key.\n" +
|
"\n".join([
|
||||||
"\tMacros can be defined using "
|
f"\t{name} \t {text}"
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
("#00FF00", "="),
|
|
||||||
(
|
|
||||||
"#FFFFFF",
|
|
||||||
", as in "
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"#AAAAAA bold",
|
|
||||||
"T = λab.a\n"
|
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
(
|
|
||||||
"#FFFFFF",
|
|
||||||
"\tRun commands using "
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"#00FF00",
|
|
||||||
":"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"#FFFFFF",
|
|
||||||
", for example "
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"#AAAAAA bold",
|
|
||||||
":help"
|
|
||||||
),
|
|
||||||
|
|
||||||
("#FF6600 bold", "\n\nCommands:\n")
|
|
||||||
] +
|
|
||||||
[
|
|
||||||
("#FFFFFF", f"\t{name} \t {text}\n")
|
|
||||||
for name, text in help_texts.items()
|
for name, text in help_texts.items()
|
||||||
]
|
]) +
|
||||||
)
|
"</cmd_text>"
|
||||||
|
),
|
||||||
|
style = utils.style
|
||||||
)
|
)
|
@ -1,5 +1,8 @@
|
|||||||
import pyparsing as pp
|
import pyparsing as pp
|
||||||
|
|
||||||
|
# Packrat gives a MAD speed boost.
|
||||||
|
pp.ParserElement.enablePackrat()
|
||||||
|
|
||||||
import lamb.tokens as tokens
|
import lamb.tokens as tokens
|
||||||
import lamb.utils as utils
|
import lamb.utils as utils
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from distutils.cmd import Command
|
from prompt_toolkit import PromptSession
|
||||||
from prompt_toolkit.formatted_text import FormattedText
|
|
||||||
|
|
||||||
import lamb.commands as commands
|
import lamb.commands as commands
|
||||||
from lamb.parser import Parser
|
from lamb.parser import Parser
|
||||||
@ -7,26 +6,18 @@ import lamb.tokens as tokens
|
|||||||
import lamb.runstatus as rs
|
import lamb.runstatus as rs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Runner:
|
class Runner:
|
||||||
def __init__(self):
|
def __init__(self, prompt_session: PromptSession, prompt_message):
|
||||||
self.macro_table = {}
|
self.macro_table = {}
|
||||||
|
self.prompt_session = prompt_session
|
||||||
|
self.prompt_message = prompt_message
|
||||||
|
|
||||||
# Maximum amount of reductions.
|
# Maximum amount of reductions.
|
||||||
# If None, no maximum is enforced.
|
# If None, no maximum is enforced.
|
||||||
self.reduction_limit: int | None = 300
|
self.reduction_limit: int | None = 300
|
||||||
|
|
||||||
def exec_command(self, command: tokens.command) -> rs.CommandStatus:
|
def prompt(self):
|
||||||
if command.name in commands.commands:
|
return self.prompt_session.prompt(message = self.prompt_message)
|
||||||
return commands.run(command, self)
|
|
||||||
|
|
||||||
# Handle unknown commands
|
|
||||||
else:
|
|
||||||
return rs.CommandStatus(
|
|
||||||
formatted_text = FormattedText([
|
|
||||||
("#FFFF00", f"Unknown command \"{command}\"")
|
|
||||||
])
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def reduce_expression(self, expr: tokens.LambdaToken) -> rs.ReduceStatus:
|
def reduce_expression(self, expr: tokens.LambdaToken) -> rs.ReduceStatus:
|
||||||
@ -63,7 +54,7 @@ class Runner:
|
|||||||
|
|
||||||
|
|
||||||
# Apply a list of definitions
|
# Apply a list of definitions
|
||||||
def run(self, line: str) -> rs.RunStatus:
|
def run(self, line: str, *, macro_only = False) -> rs.RunStatus:
|
||||||
e = Parser.parse_line(line)
|
e = Parser.parse_line(line)
|
||||||
|
|
||||||
# If this line is a macro definition, save the macro.
|
# If this line is a macro definition, save the macro.
|
||||||
@ -79,14 +70,20 @@ class Runner:
|
|||||||
macro_expr = e.exp
|
macro_expr = e.exp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
elif macro_only:
|
||||||
|
raise rs.NotAMacro()
|
||||||
|
|
||||||
# If this line is a command, do the command.
|
# If this line is a command, do the command.
|
||||||
elif isinstance(e, tokens.command):
|
elif isinstance(e, tokens.command):
|
||||||
return self.exec_command(e)
|
commands.run(e, self)
|
||||||
|
return rs.CommandStatus(cmd = e.name)
|
||||||
|
|
||||||
# If this line is a plain expression, reduce it.
|
# If this line is a plain expression, reduce it.
|
||||||
elif isinstance(e, tokens.LambdaToken):
|
elif isinstance(e, tokens.LambdaToken):
|
||||||
e.bind_variables()
|
e.bind_variables()
|
||||||
return self.reduce_expression(e)
|
return self.reduce_expression(e)
|
||||||
|
|
||||||
|
# We shouldn't ever get here.
|
||||||
else:
|
else:
|
||||||
raise TypeError(f"I don't know what to do with a {type(e)}")
|
raise TypeError(f"I don't know what to do with a {type(e)}")
|
||||||
|
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
from prompt_toolkit.formatted_text import FormattedText
|
from prompt_toolkit.formatted_text import FormattedText
|
||||||
|
from prompt_toolkit.formatted_text import HTML
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
import lamb.tokens as tokens
|
import lamb.tokens as tokens
|
||||||
|
|
||||||
|
|
||||||
|
class NotAMacro(Exception):
|
||||||
|
"""
|
||||||
|
Raised when we try to run a non-macro line
|
||||||
|
while enforcing macro_only in Runner.run().
|
||||||
|
|
||||||
|
This should be caught and elegantly presented to the user.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
class RunStatus:
|
class RunStatus:
|
||||||
"""
|
"""
|
||||||
Base class for run status.
|
Base class for run status.
|
||||||
@ -33,10 +44,10 @@ class MacroStatus(RunStatus):
|
|||||||
|
|
||||||
|
|
||||||
class StopReason(enum.Enum):
|
class StopReason(enum.Enum):
|
||||||
BETA_NORMAL = ("#FFFFFF", "β-normal form")
|
BETA_NORMAL = ("class:text", "β-normal form")
|
||||||
LOOP_DETECTED = ("#FFFF00", "loop detected")
|
LOOP_DETECTED = ("class:warn", "loop detected")
|
||||||
MAX_EXCEEDED = ("#FFFF00", "too many reductions")
|
MAX_EXCEEDED = ("class:err", "too many reductions")
|
||||||
INTERRUPT = ("#FF0000", "user interrupt")
|
INTERRUPT = ("class:warn", "user interrupt")
|
||||||
|
|
||||||
|
|
||||||
class ReduceStatus(RunStatus):
|
class ReduceStatus(RunStatus):
|
||||||
@ -63,14 +74,11 @@ class ReduceStatus(RunStatus):
|
|||||||
class CommandStatus(RunStatus):
|
class CommandStatus(RunStatus):
|
||||||
"""
|
"""
|
||||||
Returned when a command is executed.
|
Returned when a command is executed.
|
||||||
|
Doesn't do anything interesting.
|
||||||
|
|
||||||
Values:
|
Values:
|
||||||
`formatted_text`: What to print after this command is executed
|
`cmd`: The command that was run, without a colon.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, *, cmd: str):
|
||||||
self,
|
self.cmd = cmd
|
||||||
*,
|
|
||||||
formatted_text: FormattedText
|
|
||||||
):
|
|
||||||
self.formatted_text = formatted_text
|
|
@ -30,6 +30,39 @@ def autochurch(results):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
style = Style.from_dict({
|
||||||
|
# Basic formatting
|
||||||
|
"text": "#FFFFFF",
|
||||||
|
"warn": "#FFFF00",
|
||||||
|
"err": "#FF0000",
|
||||||
|
"prompt": "#00FFFF",
|
||||||
|
"ok": "#B4EC85",
|
||||||
|
|
||||||
|
# Syntax
|
||||||
|
"syn_macro": "#FF00FF",
|
||||||
|
"syn_lambda": "#FF00FF",
|
||||||
|
"syn_bound": "#FF00FF",
|
||||||
|
|
||||||
|
# Titles for reduction results
|
||||||
|
"result_header": "#B4EC85 bold",
|
||||||
|
|
||||||
|
# Command formatting
|
||||||
|
# cmd_h: section titles
|
||||||
|
# cmd_code: example snippets
|
||||||
|
# cmd_text: regular text
|
||||||
|
# cmd_key: keyboard keys, usually one character
|
||||||
|
"cmd_h": "#FF6600 bold",
|
||||||
|
"cmd_code": "#AAAAAA italic",
|
||||||
|
"cmd_text": "#FFFFFF",
|
||||||
|
"cmd_key": "#B4EC85 bold",
|
||||||
|
|
||||||
|
# Only used in greeting
|
||||||
|
"_v": "#B4EC85 bold",
|
||||||
|
"_l": "#FF6600 bold",
|
||||||
|
"_s": "#B4EC85 bold",
|
||||||
|
"_p": "#AAAAAA"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def show_greeting():
|
def show_greeting():
|
||||||
# | _.._ _.|_
|
# | _.._ _.|_
|
||||||
@ -62,19 +95,4 @@ def show_greeting():
|
|||||||
"<_s> A λ calculus engine</_s>",
|
"<_s> A λ calculus engine</_s>",
|
||||||
"<_p> Type :help for help</_p>",
|
"<_p> Type :help for help</_p>",
|
||||||
""
|
""
|
||||||
])), style = Style.from_dict({
|
])), style = style)
|
||||||
# Heading
|
|
||||||
"_h": "#FFFFFF bold",
|
|
||||||
|
|
||||||
# Version
|
|
||||||
"_v": "#B4EC85 bold",
|
|
||||||
|
|
||||||
# Lambda
|
|
||||||
"_l": "#FF6600 bold",
|
|
||||||
|
|
||||||
# Subtitle
|
|
||||||
"_s": "#B4EC85 bold",
|
|
||||||
|
|
||||||
# :help message
|
|
||||||
"_p": "#AAAAAA"
|
|
||||||
}))
|
|
Reference in New Issue
Block a user