Skip to content

Commit 7e9c4a3

Browse files
committed
Add letrec and letrec*
1 parent 57422e2 commit 7e9c4a3

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

Diff for: syntax.c

+34
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,38 @@ static StObject syntax_let1(StObject module, StObject expr)
7575
return St_SyntaxExpand(module, ret);
7676
}
7777

78+
static StObject syntax_letrec(StObject module, StObject expr)
79+
{
80+
// (letrec <bindings> <body>)
81+
// <bindings> ::= ((sym <expr>)*)
82+
// =>
83+
// ((lambda () (define s1 e1) (define e2 s2) ... body))
84+
85+
if (St_Length(expr) < 2)
86+
{
87+
St_Error("letrec: malformed letrec");
88+
}
89+
90+
StObject bindings = ST_CADR(expr);
91+
StObject body = ST_CDDR(expr);
92+
93+
validate_bindings(bindings);
94+
95+
StObject ds = Nil, t = Nil;
96+
97+
ST_FOREACH(p, bindings) {
98+
StObject s = ST_CAAR(p);
99+
StObject e = ST_CAR(ST_CDAR(p));
100+
101+
ST_APPEND1(ds, t, ST_LIST3(I("define"), s, St_SyntaxExpand(module, e)));
102+
}
103+
104+
return ST_LIST1(St_Cons(I("lambda"),
105+
St_Cons(Nil,
106+
St_Cons(St_Cons(I("begin"), ds),
107+
St_SyntaxExpand(module, body)))));
108+
}
109+
78110
static StObject syntax_define(StObject module, StObject expr)
79111
{
80112
if (St_Length(expr) < 2)
@@ -180,6 +212,8 @@ void St_InitSyntax(void)
180212
St_AddSyntax(m, "let", syntax_let);
181213
St_AddSyntax(m, "let*", syntax_let);
182214
St_AddSyntax(m, "let1", syntax_let1);
215+
St_AddSyntax(m, "letrec", syntax_letrec);
216+
St_AddSyntax(m, "letrec*", syntax_letrec);
183217
St_AddSyntax(m, "define", syntax_define);
184218
St_AddSyntax(m, "cond", syntax_cond);
185219
St_AddSyntax(m, "case", syntax_case);

Diff for: test/test.scm

+12
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@
143143

144144
(assert 1 (let1 x 1 x) 'let1_0)
145145

146+
(assert #t (letrec ((odd? (lambda (n) (even? (- n 1))))
147+
(even? (lambda (n) (if (= n 0) #t (odd? (- n 1))))))
148+
(odd? 5))
149+
'letrec_0)
150+
151+
(define x ())
152+
(letrec* ((a (begin (set! x (cons 1 x)) x))
153+
(c (begin (set! x (cons 2 x)) x)))
154+
#t)
155+
(assert '(2 1) x 'letrec*_0)
156+
157+
146158
(define x 1)
147159
(set! x 2)
148160
(assert 2 x 'set!_0)

0 commit comments

Comments
 (0)