Skip to content

Commit aefd5a0

Browse files
committed
add apply primitive
1 parent 55a9531 commit aefd5a0

File tree

4 files changed

+63
-6
lines changed

4 files changed

+63
-6
lines changed

src/eval.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ static void check_prim_arity(obj f, obj args) {
109109
minim_error1("eval_expr", "primitive arity unsupported", Mfixnum(Mprim_arity(f)));
110110
}
111111

112+
// performs `apply` primitive
113+
// flattens the last argument (checks that it is a list)
114+
static obj do_apply(obj args) {
115+
obj hd;
116+
117+
if (Mnullp(Mcdr(args))) {
118+
if (!Mlistp(Mcar(args)))
119+
minim_error1("apply", "expected list?", Mcar(args));
120+
return Mcar(args);
121+
} else {
122+
hd = args;
123+
while (!Mnullp(Mcddr(args))) args = Mcdr(args);
124+
125+
if (!Mlistp(Mcadr(args)))
126+
minim_error1("apply", "expected list?", Mcadr(args));
127+
Mcdr(args) = Mcadr(args);
128+
129+
return hd;
130+
}
131+
}
132+
112133
// performs `values` primitive
113134
// if there is only 1 argument, the argument is returned
114135
// otherwise, the arguments are written to the values buffer
@@ -212,11 +233,14 @@ static obj do_prim(obj f, obj args) {
212233

213234
switch (Mprim_arity(f))
214235
{
215-
case 0: return fn();
216-
case 1: return fn(Mcar(args));
217-
case 2: return fn(Mcar(args), Mcadr(args));
218-
case 3: return fn(Mcar(args), Mcadr(args), Mcaddr(args));
219-
236+
case 0:
237+
return fn();
238+
case 1:
239+
return fn(Mcar(args));
240+
case 2:
241+
return fn(Mcar(args), Mcadr(args));
242+
case 3:
243+
return fn(Mcar(args), Mcadr(args), Mcaddr(args));
220244
default:
221245
minim_error1("eval_expr", "primitive arity unsupported", Mfixnum(Mprim_arity(f)));
222246
}
@@ -440,7 +464,13 @@ static obj eval_k(obj e) {
440464
if (Mprimp(f)) {
441465
check_prim_arity(f, args);
442466
if (Mprim_specialp(f)) {
443-
x = do_special_prim(f, args);
467+
if (f == apply_prim) {
468+
f = Mcar(args);
469+
args = do_apply(Mcdr(args));
470+
goto do_app;
471+
} else {
472+
x = do_special_prim(f, args);
473+
}
444474
} else {
445475
x = do_prim(f, args);
446476
}

src/minim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ extern obj fx_le_prim;
479479
extern obj fx_gt_prim;
480480
extern obj fx_lt_prim;
481481

482+
extern obj apply_prim;
482483
extern obj callcc_prim;
483484
extern obj callwv_prim;
484485
extern obj exit_prim;

src/prim.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ obj fx_le_prim;
2424
obj fx_gt_prim;
2525
obj fx_lt_prim;
2626

27+
obj apply_prim;
2728
obj callcc_prim;
2829
obj callwv_prim;
2930
obj exit_prim;
@@ -44,6 +45,7 @@ proc1(nullp_proc, x, Mbool(Mnullp(x)))
4445
proc1(car_proc, x, Mcar(x))
4546
proc1(cdr_proc, x, Mcdr(x))
4647

48+
uncallable_proc(apply_proc);
4749
uncallable_proc(callcc_proc);
4850
uncallable_proc(callwv_proc);
4951
uncallable_proc(dynwind_proc);
@@ -78,6 +80,8 @@ void init_prims(void) {
7880

7981
void_prim = Mprim(void_proc, -1, "void");
8082

83+
apply_prim = Mprim(apply_proc, -3, "apply");
84+
Mprim_specialp(apply_prim) = 1;
8185
callcc_prim = Mprim(callcc_proc, 1, "call-with-current-continuation");
8286
Mprim_specialp(callcc_prim) = 1;
8387
callwv_prim = Mprim(callwv_proc, 2, "call-with-values");
@@ -121,6 +125,7 @@ obj prim_env(obj env) {
121125
env_add_prim(env, fx_gt_prim);
122126
env_add_prim(env, fx_lt_prim);
123127

128+
env_add_prim(env, apply_prim);
124129
env_insert(env, Mintern("call/cc"), callcc_prim);
125130
env_add_prim(env, callcc_prim);
126131
env_add_prim(env, callwv_prim);

tests/prims.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,26 @@ int test_dynamic_wind(void) {
148148
return passed;
149149
}
150150

151+
int test_apply(void) {
152+
passed = 1;
153+
154+
check_equal("(apply list '())", "()");
155+
check_equal("(apply list 1 '())", "(1)");
156+
check_equal("(apply list 1 '(2 3))", "(1 2 3)");
157+
check_equal("(apply list 1 2 3 '())", "(1 2 3)");
158+
check_equal("(apply list 1 2 3 '(4 5))", "(1 2 3 4 5)");
159+
160+
check_equal(
161+
"(apply call-with-values "
162+
"(cons (lambda () 1) "
163+
"(cons (lambda (x) (cons x 2)) "
164+
"'())))",
165+
"(1 . 2)"
166+
);
167+
168+
return passed;
169+
}
170+
151171
int test_misc(void) {
152172
passed = 1;
153173

@@ -169,6 +189,7 @@ int main(int argc, char **argv) {
169189
log_test("call-with-values", test_callwv, return_code);
170190
log_test("call/cc", test_callcc, return_code);
171191
log_test("dynamic-wind", test_dynamic_wind, return_code);
192+
log_test("apply", test_apply, return_code);
172193
log_test("misc", test_misc, return_code);
173194

174195
minim_shutdown(return_code);

0 commit comments

Comments
 (0)