-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscheme_classes.py
146 lines (112 loc) · 4.54 KB
/
scheme_classes.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import sys
import os
from pair import *
from ucb import main, trace
class SchemeError(Exception):
"""Exception indicating an error in a Scheme program."""
################
# Environments #
################
class Frame:
"""An environment frame binds Scheme symbols to Scheme values."""
def __init__(self, parent):
"""An empty frame with parent frame PARENT (which may be None)."""
self.bindings = {}
self.parent = parent
def __repr__(self):
if self.parent is None:
return '<Global Frame>'
s = sorted(['{0}: {1}'.format(k, v) for k, v in self.bindings.items()])
return '<{{{0}}} -> {1}>'.format(', '.join(s), repr(self.parent))
def define(self, symbol, value):
"""Define Scheme SYMBOL to have VALUE."""
# BEGIN PROBLEM 1
self.bindings[symbol] = value
# END PROBLEM 1
def lookup(self, symbol):
"""Return the value bound to SYMBOL. Errors if SYMBOL is not found."""
# BEGIN PROBLEM 1
if self is not None:
if symbol in self.bindings.keys() and self:
# print("DEBUG:",symbol in self.bindings)
return self.bindings[symbol]
elif self.parent:
return self.parent.lookup(symbol)
raise SchemeError('unknown identifier: {0}'.format(symbol))
# END PROBLEM 1
def make_child_frame(self, formals, vals):
"""Return a new local frame whose parent is SELF, in which the symbols
in a Scheme list of formal parameters FORMALS are bound to the Scheme
values in the Scheme list VALS. Both FORMALS and VALS are represented as Pairs.
Raise an error if too many or too few
vals are given.
>>> env = create_global_frame()
>>> formals, expressions = read_line('(a b c)'), read_line('(1 2 3)')
>>> env.make_child_frame(formals, expressions)
<{a: 1, b: 2, c: 3} -> <Global Frame>>
"""
if len(formals) != len(vals):
raise SchemeError('Incorrect number of arguments to function call')
# BEGIN PROBLEM 8
new_frame = Frame(self)
while(formals is not nil):
new_frame.define(formals.first, vals.first)
formals = formals.rest
vals = vals.rest
return new_frame
# END PROBLEM 8
##############
# Procedures #
##############
class Procedure:
"""The the base class for all Procedure classes."""
class BuiltinProcedure(Procedure):
"""A Scheme procedure defined as a Python function."""
def __init__(self, py_func, expect_env=False, name='builtin'):
self.name = name
self.py_func = py_func
self.expect_env = expect_env
def __str__(self):
return '#[{0}]'.format(self.name)
class LambdaProcedure(Procedure):
"""A procedure defined by a lambda expression or a define form."""
def __init__(self, formals, body, env):
"""A procedure with formal parameter list FORMALS (a Scheme list),
whose body is the Scheme list BODY, and whose parent environment
starts with Frame ENV."""
assert isinstance(env, Frame), "env must be of type Frame"
from scheme_utils import validate_type, scheme_listp
validate_type(formals, scheme_listp, 0, 'LambdaProcedure')
validate_type(body, scheme_listp, 1, 'LambdaProcedure')
self.formals = formals
self.body = body
self.env = env
def __str__(self):
return str(Pair('lambda', Pair(self.formals, self.body)))
def __repr__(self):
return 'LambdaProcedure({0}, {1}, {2})'.format(
repr(self.formals), repr(self.body), repr(self.env))
class MuProcedure(Procedure):
"""A procedure defined by a mu expression, which has dynamic scope.
_________________
< Scheme is cool! >
-----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
"""
def __init__(self, formals, body):
"""A procedure with formal parameter list FORMALS (a Scheme list) and
Scheme list BODY as its definition."""
self.formals = formals
self.body = body
def __str__(self):
return str(Pair('mu', Pair(self.formals, self.body)))
def __repr__(self):
return 'MuProcedure({0}, {1})'.format(
repr(self.formals), repr(self.body))
class MacroProcedure(LambdaProcedure):
"""A macro: a special form that operates on its unevaluated operands to
create an expression that is evaluated in place of a call."""