Skip to content

Commit 2f2f87d

Browse files
committed
sync from Atlas
1 parent 6527037 commit 2f2f87d

File tree

16 files changed

+1730
-115
lines changed

16 files changed

+1730
-115
lines changed
+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
"""
2+
Doctests for `parse`
3+
--------------------
4+
5+
# tag::PARSE[]
6+
>>> from lis import parse
7+
>>> parse('1.5')
8+
1.5
9+
>>> parse('ni!')
10+
'ni!'
11+
>>> parse('(gcd 18 45)')
12+
['gcd', 18, 45]
13+
>>> parse('''
14+
... (define double
15+
... (lambda (n)
16+
... (* n 2)))
17+
... ''')
18+
['define', 'double', ['lambda', ['n'], ['*', 'n', 2]]]
19+
20+
# end::PARSE[]
21+
22+
Doctest for `Environment`
23+
-------------------------
24+
25+
# tag::ENVIRONMENT[]
26+
>>> from lis import Environment
27+
>>> inner_env = {'a': 2}
28+
>>> outer_env = {'a': 0, 'b': 1}
29+
>>> env = Environment(inner_env, outer_env)
30+
>>> env['a'] = 111 # <1>
31+
>>> env['c'] = 222
32+
>>> env
33+
Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 1})
34+
>>> env.change('b', 333) # <2>
35+
>>> env
36+
Environment({'a': 111, 'c': 222}, {'a': 0, 'b': 333})
37+
38+
# end::ENVIRONMENT[]
39+
40+
Doctests for `evaluate`
41+
-----------------------
42+
43+
# tag::EVAL_NUMBER[]
44+
>>> from lis import parse, evaluate, standard_env
45+
>>> evaluate(parse('1.5'), {})
46+
1.5
47+
48+
# end::EVAL_NUMBER[]
49+
50+
# tag::EVAL_SYMBOL[]
51+
>>> from lis import standard_env
52+
>>> evaluate(parse('+'), standard_env())
53+
<built-in function add>
54+
>>> evaluate(parse('ni!'), standard_env())
55+
Traceback (most recent call last):
56+
...
57+
KeyError: 'ni!'
58+
59+
# end::EVAL_SYMBOL[]
60+
61+
62+
# tag::EVAL_QUOTE[]
63+
>>> evaluate(parse('(quote no-such-name)'), standard_env())
64+
'no-such-name'
65+
>>> evaluate(parse('(quote (99 bottles of beer))'), standard_env())
66+
[99, 'bottles', 'of', 'beer']
67+
>>> evaluate(parse('(quote (/ 10 0))'), standard_env())
68+
['/', 10, 0]
69+
70+
# end::EVAL_QUOTE[]
71+
72+
# tag::EVAL_IF[]
73+
>>> evaluate(parse('(if (= 3 3) 1 0))'), standard_env())
74+
1
75+
>>> evaluate(parse('(if (= 3 4) 1 0))'), standard_env())
76+
0
77+
78+
# end::EVAL_IF[]
79+
80+
81+
# tag::EVAL_LAMBDA[]
82+
>>> expr = '(lambda (a b) (* (/ a b) 100))'
83+
>>> f = evaluate(parse(expr), standard_env())
84+
>>> f # doctest: +ELLIPSIS
85+
<lis.Procedure object at 0x...>
86+
>>> f(15, 20)
87+
75.0
88+
89+
# end::EVAL_LAMBDA[]
90+
91+
# tag::EVAL_DEFINE[]
92+
>>> global_env = standard_env()
93+
>>> evaluate(parse('(define answer (* 7 6))'), global_env)
94+
>>> global_env['answer']
95+
42
96+
97+
# end::EVAL_DEFINE[]
98+
99+
# tag::EVAL_DEFUN[]
100+
>>> global_env = standard_env()
101+
>>> percent = '(define (% a b) (* (/ a b) 100))'
102+
>>> evaluate(parse(percent), global_env)
103+
>>> global_env['%'] # doctest: +ELLIPSIS
104+
<lis.Procedure object at 0x...>
105+
>>> global_env['%'](170, 200)
106+
85.0
107+
108+
# end::EVAL_DEFUN[]
109+
110+
function call:
111+
112+
# tag::EVAL_CALL[]
113+
>>> evaluate(parse('(% (* 12 14) (- 500 100))'), global_env)
114+
42.0
115+
116+
# end::EVAL_CALL[]
117+
118+
# tag::EVAL_SYNTAX_ERROR[]
119+
>>> evaluate(parse('(lambda is not like this)'), standard_env())
120+
Traceback (most recent call last):
121+
...
122+
SyntaxError: (lambda is not like this)
123+
124+
# end::EVAL_SYNTAX_ERROR[]
125+
126+
"""
127+
128+
import math
129+
130+
from lis import run
131+
132+
133+
fact_src = """
134+
(define (! n)
135+
(if (< n 2)
136+
1
137+
(* n (! (- n 1)))
138+
)
139+
)
140+
(! 42)
141+
"""
142+
def test_factorial():
143+
got = run(fact_src)
144+
assert got == 1405006117752879898543142606244511569936384000000000
145+
assert got == math.factorial(42)
146+
147+
148+
gcd_src = """
149+
(define (mod m n)
150+
(- m (* n (// m n))))
151+
(define (gcd m n)
152+
(if (= n 0)
153+
m
154+
(gcd n (mod m n))))
155+
(display (gcd 18 45))
156+
"""
157+
def test_gcd(capsys):
158+
run(gcd_src)
159+
captured = capsys.readouterr()
160+
assert captured.out == '9\n'
161+
162+
163+
quicksort_src = """
164+
(define (quicksort lst)
165+
(if (null? lst)
166+
lst
167+
(begin
168+
(define pivot (car lst))
169+
(define rest (cdr lst))
170+
(append
171+
(quicksort
172+
(filter (lambda (x) (< x pivot)) rest))
173+
(list pivot)
174+
(quicksort
175+
(filter (lambda (x) (>= x pivot)) rest)))
176+
)
177+
)
178+
)
179+
(quicksort (list 2 1 6 3 4 0 8 9 7 5))
180+
"""
181+
def test_quicksort():
182+
got = run(quicksort_src)
183+
assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
184+
185+
186+
# Example from Structure and Interpretation of Computer Programs
187+
# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html
188+
189+
newton_src = """
190+
(define (sqrt x)
191+
(sqrt-iter 1.0 x))
192+
(define (sqrt-iter guess x)
193+
(if (good-enough? guess x)
194+
guess
195+
(sqrt-iter (improve guess x) x)))
196+
(define (good-enough? guess x)
197+
(< (abs (- (* guess guess) x)) 0.001))
198+
(define (improve guess x)
199+
(average guess (/ x guess)))
200+
(define (average x y)
201+
(/ (+ x y) 2))
202+
(sqrt 123454321)
203+
"""
204+
def test_newton():
205+
got = run(newton_src)
206+
assert math.isclose(got, 11111)
207+
208+
209+
closure_src = """
210+
(define (make-adder increment)
211+
(lambda (x) (+ increment x))
212+
)
213+
(define inc (make-adder 1))
214+
(inc 99)
215+
"""
216+
def test_closure():
217+
got = run(closure_src)
218+
assert got == 100
219+
220+
closure_with_change_src = """
221+
(define (make-counter)
222+
(define n 0)
223+
(lambda ()
224+
(set! n (+ n 1))
225+
n)
226+
)
227+
(define counter (make-counter))
228+
(display (counter))
229+
(display (counter))
230+
(display (counter))
231+
"""
232+
def test_closure_with_change(capsys):
233+
run(closure_with_change_src)
234+
captured = capsys.readouterr()
235+
assert captured.out == '1\n2\n3\n'
236+
237+
238+
239+
# tag::RUN_AVERAGER[]
240+
closure_averager_src = """
241+
(define (make-averager)
242+
(define count 0)
243+
(define total 0)
244+
(lambda (new-value)
245+
(set! count (+ count 1))
246+
(set! total (+ total new-value))
247+
(/ total count)
248+
)
249+
)
250+
(define avg (make-averager))
251+
(avg 10)
252+
(avg 11)
253+
(avg 15)
254+
"""
255+
def test_closure_averager():
256+
got = run(closure_averager_src)
257+
assert got == 12.0
258+
# end::RUN_AVERAGER[]

0 commit comments

Comments
 (0)