-
Notifications
You must be signed in to change notification settings - Fork 1
/
cfg.py
127 lines (90 loc) · 3.33 KB
/
cfg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import sys
import string
# Scanning/parsing related constants
WHITESPACE = string.whitespace
PARENS = "()"
LINE_COMMENT_CHAR = ";"
STRING_DELIMITER = '"'
STRING_ESCAPE_CHAR = "\\"
SPECIAL_CHARS = WHITESPACE + PARENS + LINE_COMMENT_CHAR + STRING_DELIMITER
# Repl prompt string
PROMPT = "tl2> "
HELP_TEXT = """
Enter expressions at the prompt.
- Anything starting with ; is a comment and will be ignored.
- Any run of digits (with optional minus sign) is an integer literal.
- () is the empty list, nil.
- Anything in "double quotes" is a string literal. Special characters
can be escaped with backslashes.
- A series of expressions enclosed in parentheses is a function or
macro call.
- Anything else is a symbol, which returns the value bound to it or
errors if it is unbound; if quoted with q, it is kept unevaluated.
The builtin functions and macros are: cons, head, tail, +, -, *, /,
mod, <, =, same-type?, unparse, write, locals, eval, def, if, q,
and load. Most of these also have abbreviated names, unless you have
invoked the interpreter with --no-short-names or --builtins-only:
cons -> c, head -> h, tail -> t, mod -> %, same-type? -> y,
unparse -> u, write -> w, eval -> v, def -> d, if -> ?.
The core library defines many more functions and macros. It is loaded
by default, unless you have invoked the interpreter with --no-library
or --builtins-only. Some library functions also have abbreviated names.
You can create your own functions. The easiest way is to use the lambda
macro from the library: (lambda (x) (+ x 2)) is a function that adds 2
to its argument. To create a named function, bind it to a name using def.
Special features in the interactive prompt:
- The name _ is bound to the value of the last evaluated expression.
- (restart) clears all user-defined names, starting over from scratch.
- (help) displays this help text.
- (quit) ends the session.
"""
# Max param count of variadic builtins
UNLIMITED = float("inf")
# The empty list, nil
nil = []
# Shortcut functions for print without newline and print to stderr
def write(*args):
print(*args, end="")
def error(*args):
print("Error:", *args, file=sys.stderr)
def warn(*args):
print("Warning:", *args, file=sys.stderr)
def interrupted_error():
error("calculation interrupted by user.")
def recursion_error():
error("recursion depth exceeded. How could you forget to use tail calls?!")
def tl_truthy(value):
"""Is the value truthy in tinylisp?"""
if value == nil or value == "" or value == 0:
return False
else:
return True
def tl_type(value):
if isinstance(value, list):
return "List"
elif isinstance(value, int):
return "Integer"
elif isinstance(value, str):
return "String"
elif isinstance(value, Symbol):
return "Symbol"
else:
return "Builtin"
# Exception that is raised by the (quit) macro
class UserQuit(BaseException):
pass
# Class for symbols to distinguish them from strings
class Symbol:
def __init__(self, name):
self.name = str(name)
def __eq__(self, rhs):
if isinstance(rhs, Symbol):
return self.name == rhs.name
else:
return self.name == rhs
def __str__(self):
return self.name
def __repr__(self):
return f"Symbol({self.name!r})"
def __hash__(self):
return hash(repr(self))