-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscheme.py
116 lines (99 loc) · 3.98 KB
/
scheme.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
"""A Scheme interpreter and its read-eval-print loop."""
import sys
import os
sys.path.append("scheme_reader")
from scheme_classes import *
from scheme_forms import *
from scheme_eval_apply import *
from scheme_builtins import *
from scheme_reader import *
from ucb import main, trace
################
# Input/Output #
################
def read_eval_print_loop(next_line, env, interactive=False, quiet=False,
startup=False, load_files=(), report_errors=False):
"""Read and evaluate input until an end of file or keyboard interrupt."""
if startup:
for filename in load_files:
scheme_load(filename, True, env)
while True:
try:
src = next_line()
while src.end_of_line():
src.pop_first()
while not src.end_of_line():
expression = scheme_read(src)
result = scheme_eval(expression, env)
if not quiet and result is not None:
print(repl_str(result))
except (SchemeError, SyntaxError, ValueError, RuntimeError) as err:
if report_errors:
if isinstance(err, SyntaxError):
err = SchemeError(err)
raise err
if (isinstance(err, RuntimeError) and
'maximum recursion depth exceeded' not in getattr(err, 'args')[0]):
raise
elif isinstance(err, RuntimeError):
print('Error: maximum recursion depth exceeded')
else:
print('Error:', err)
except KeyboardInterrupt: # <Control>-C
if not startup:
raise
print()
print('KeyboardInterrupt')
if not interactive:
return
except EOFError: # <Control>-D, etc.
print()
return
def add_builtins(frame, funcs_and_names):
"""Enter bindings in FUNCS_AND_NAMES into FRAME, an environment frame,
as built-in procedures. Each item in FUNCS_AND_NAMES has the form
(NAME, PYTHON-FUNCTION, INTERNAL-NAME)."""
for name, py_func, proc_name, expect_env in funcs_and_names:
frame.define(name, BuiltinProcedure(py_func, name=proc_name, expect_env=expect_env))
def create_global_frame():
"""Initialize and return a single-frame environment with built-in names."""
env = Frame(None)
env.define('eval',
BuiltinProcedure(scheme_eval, True, 'eval'))
env.define('apply',
BuiltinProcedure(complete_apply, True, 'apply'))
env.define('undefined', None)
add_builtins(env, BUILTINS)
return env
@main
def run(*argv):
import argparse
parser = argparse.ArgumentParser(description='CS 61A Scheme Interpreter')
parser.add_argument('--pillow-turtle', action='store_true',
help='run with pillow-based turtle. This is much faster for rendering but there is no GUI')
parser.add_argument('--turtle-save-path', default=None,
help='save the image to this location when done')
parser.add_argument('-load', '-i', action='store_true',
help='run file interactively')
parser.add_argument('file', nargs='?',
type=argparse.FileType('r'), default=None,
help='Scheme file to run')
args = parser.parse_args()
import builtins
builtins.TK_TURTLE = not args.pillow_turtle
builtins.TURTLE_SAVE_PATH = args.turtle_save_path
sys.path.insert(0, '')
next_line = buffer_input
interactive = True
load_files = []
if args.file is not None:
if args.load:
load_files.append(getattr(args.file, 'name'))
else:
lines = args.file.readlines()
def next_line():
return buffer_lines(lines)
interactive = False
read_eval_print_loop(next_line, create_global_frame(), startup=True,
interactive=interactive, load_files=load_files)
tscheme_exitonclick()