Import of Bhuna 0.5 sources.
catseye
11 years ago
0 | // Ackermann function. Derived from: | |
1 | // $Id: ackermann.lua.html,v 1.5 2004/07/03 07:11:33 bfulgham Exp $ | |
2 | // http://www.bagley.org/~doug/shootout/ | |
3 | ||
4 | Ack = ^ M,N { | |
5 | if M = 0 | |
6 | return N + 1 | |
7 | else if N = 0 | |
8 | return Ack(M - 1, 1) | |
9 | else | |
10 | return Ack(M - 1, Ack(M, (N - 1))) | |
11 | } | |
12 | ||
13 | I = 5 | |
14 | while I > 0 { | |
15 | Num = 7 | |
16 | Print "Ack(3,", Num, "): ", Ack(3, Num), EoL | |
17 | I = I - 1 | |
18 | }⏎ |
0 | // Ackermann function. Derived from: | |
1 | // $Id: ackermann.lua.html,v 1.5 2004/07/03 07:11:33 bfulgham Exp $ | |
2 | // http://www.bagley.org/~doug/shootout/ | |
3 | ||
4 | Ack = ^ M,N { | |
5 | if M = 0 | |
6 | return N + 1 | |
7 | else if N = 0 | |
8 | return Ack(M - 1, 1) | |
9 | else | |
10 | return Ack(M - 1, Ack(M, (N - 1))) | |
11 | } | |
12 | ||
13 | Num = 9 | |
14 | Print "Ack(3,", Num, "): ", Ack(3, Num), EoL |
0 | Print 12 / (6 / 2) |
0 | Fib = ^ X { | |
1 | if X > 2 | |
2 | return Fib(X - 1) + Fib(X - 2) | |
3 | else | |
4 | return 1 | |
5 | } | |
6 | ||
7 | MakeFibPrinter = ^ X { | |
8 | return ^ { Print "Fib(", X, ")=", Fib(X), EoL } | |
9 | } | |
10 | ||
11 | I = 1 | |
12 | while I <= 25 { | |
13 | Q = MakeFibPrinter(I) | |
14 | Spawn Q | |
15 | I = I + 1 | |
16 | } |
0 | // mutual tail recursion. | |
1 | ||
2 | // dummy function to get decls/type checking OK | |
3 | ||
4 | F = ^ A { return A } | |
5 | ||
6 | G = ^ A, B { | |
7 | if A > 0 { | |
8 | Print "In G, A = ", A, " and B = ", B, EoL | |
9 | return F(A-1) | |
10 | } else { | |
11 | Print "End of G", EoL | |
12 | return 0 | |
13 | } | |
14 | } | |
15 | ||
16 | F = ^ A { | |
17 | if A > 0 { | |
18 | Print "In F, A = ", A, EoL | |
19 | return G(A-1, A+1) | |
20 | } else { | |
21 | Print "End of F", EoL | |
22 | return 0 | |
23 | } | |
24 | } | |
25 | ||
26 | Print "F(100000)=", F(100000), EoL |
0 | A = [1, 2, 3] | |
1 | B = A | |
2 | ||
3 | PrintAB = ^ { | |
4 | Print "A = ", A, EoL | |
5 | Print "B = ", B, EoL | |
6 | } | |
7 | ||
8 | PrintAB; | |
9 | ||
10 | B[2] = ["zing", "zang", "bar"] | |
11 | PrintAB; | |
12 | ||
13 | B[2][2] = "foo" | |
14 | PrintAB; |
0 | F = ^ { | |
1 | I = 10 | |
2 | while I > 0 { | |
3 | Print "F was spawned!", EoL | |
4 | I = I - 1 | |
5 | } | |
6 | } | |
7 | ||
8 | Print "Spawning F..." | |
9 | ||
10 | Spawn F | |
11 | ||
12 | Print "hello", EoL |
0 | A = 1 | |
1 | T = A | |
2 | T = 2 | |
3 | Print "A=",A," T=",T, EoL | |
4 | A = 57 | |
5 | Print "A=",A," T=",T, EoL | |
6 | T = 1 | |
7 | Print "A=",A," T=",T, EoL |
0 | PROG= bhuna | |
1 | SRCS= report.c \ | |
2 | scan.c parse.c \ | |
3 | symbol.c ast.c \ | |
4 | type.c \ | |
5 | mem.c pool.c \ | |
6 | list.c atom.c buffer.c closure.c dict.c value.c \ | |
7 | activation.c eval.c \ | |
8 | gen.c vm.c \ | |
9 | builtin.c \ | |
10 | main.c | |
0 | SUBDIR=lib modules driver | |
11 | 1 | |
12 | CFLAGS+=-DPOOL_VALUES | |
13 | CFLAGS+=-DREFCOUNTING_MACROS | |
14 | CFLAGS+=-DINLINE_BUILTINS | |
15 | CFLAGS+=-Wall -I/usr/local/include | |
16 | .ifndef NODEBUG | |
17 | CFLAGS+=-g -DDEBUG | |
18 | .else | |
19 | CFLAGS+=-DNDEBUG | |
20 | .endif | |
2 | strip: | |
3 | ( cd lib && make strip ) | |
4 | ( cd modules && make strip ) | |
5 | ( cd driver && make strip ) | |
21 | 6 | |
22 | .ifdef OPTIMIZED | |
23 | CFLAGS+=-O2 -finline-functions | |
24 | .endif | |
25 | .ifdef PROFILED | |
26 | CFLAGS+=-pg | |
27 | .endif | |
28 | ||
29 | NOMAN= y | |
30 | ||
31 | # DESTDIR=/usr/local/sbin | |
32 | strip: bhuna | |
33 | strip bhuna | |
34 | ls -lah bhuna | |
35 | ls -la bhuna | |
36 | ||
37 | .include <bsd.prog.mk> | |
7 | .include <bsd.subdir.mk> |
0 | #CFLAGS+=-DPOOL_VALUES | |
1 | CFLAGS+=-DHASH_CONSING | |
2 | CFLAGS+=-DINLINE_BUILTINS | |
3 | CFLAGS+=-Wall | |
4 | ||
5 | #-I/usr/local/include | |
6 | ||
7 | .ifndef NODEBUG | |
8 | CFLAGS+=-g -DDEBUG | |
9 | .else | |
10 | CFLAGS+=-DNDEBUG | |
11 | .endif | |
12 | ||
13 | .ifdef OPTIMIZED | |
14 | CFLAGS+=-Os -finline-functions | |
15 | .endif | |
16 | ||
17 | .ifdef PROFILED | |
18 | CFLAGS+=-pg | |
19 | .endif |
0 | #include <assert.h> | |
1 | #include <stdlib.h> | |
2 | #include <stdio.h> | |
3 | #include <string.h> | |
4 | ||
5 | #include "mem.h" | |
6 | #include "activation.h" | |
7 | #include "value.h" | |
8 | #include "list.h" | |
9 | #include "closure.h" | |
10 | ||
11 | #define VALARY(a,i) \ | |
12 | ((struct value **)((char *)a + sizeof(struct activation)))[i] | |
13 | ||
14 | #ifdef DEBUG | |
15 | extern int trace_activations; | |
16 | extern int activations_allocated; | |
17 | extern int activations_freed; | |
18 | #endif | |
19 | ||
20 | extern struct activation *current_ar; | |
21 | extern int gc_trigger; | |
22 | extern int gc_target; | |
23 | ||
24 | static struct activation *a_head = NULL; | |
25 | static int a_count = 0; | |
26 | ||
27 | #define A_STACK_SIZE 65536 | |
28 | ||
29 | unsigned char a_stack[A_STACK_SIZE]; | |
30 | unsigned char *a_sp = a_stack; | |
31 | ||
32 | struct activation * | |
33 | activation_new_on_heap(int size, struct activation *caller, struct activation *enclosing) | |
34 | { | |
35 | struct activation *a; | |
36 | ||
37 | if (a_count > gc_target) { | |
38 | /*printf("GC!\n");*/ | |
39 | #ifdef DEBUG | |
40 | if (trace_activations > 1) { | |
41 | printf("[ARC] GARBAGE COLLECTION STARTED on %d activation records!!!\n", | |
42 | a_count); | |
43 | activation_dump(current_ar, 0); | |
44 | printf("\n"); | |
45 | } | |
46 | #endif | |
47 | activation_gc(); | |
48 | #ifdef DEBUG | |
49 | if (trace_activations > 1) { | |
50 | printf("[ARC] GARBAGE COLLECTION FINISHED, now %d activation records!!!\n", | |
51 | a_count); | |
52 | activation_dump(current_ar, 0); | |
53 | printf("\n"); | |
54 | } | |
55 | #endif | |
56 | /* | |
57 | * Slide the target to account for the fact that there | |
58 | * are now 'a_count' activation records in existence. | |
59 | * Only GC when there are gc_trigger *more* ar's. | |
60 | */ | |
61 | gc_target = a_count + gc_trigger; | |
62 | } | |
63 | ||
64 | a = bhuna_malloc(sizeof(struct activation) + | |
65 | sizeof(struct value *) * size); | |
66 | /*bzero(a, sizeof(struct activation) + | |
67 | sizeof(struct value *) * size);*/ | |
68 | a->size = size; | |
69 | a->caller = caller; | |
70 | a->enclosing = enclosing; | |
71 | a->marked = 0; | |
72 | ||
73 | /* | |
74 | * Link up to our GC list. | |
75 | */ | |
76 | a->next = a_head; | |
77 | a_head = a; | |
78 | ||
79 | #ifdef DEBUG | |
80 | if (trace_activations > 1) { | |
81 | printf("[ARC] created on HEAP"); | |
82 | activation_dump(a, -1); | |
83 | printf("\n"); | |
84 | } | |
85 | activations_allocated++; | |
86 | #endif | |
87 | ||
88 | a_count++; | |
89 | return(a); | |
90 | } | |
91 | ||
92 | struct activation * | |
93 | activation_new_on_stack(int size, struct activation *caller, struct activation *enclosing) | |
94 | { | |
95 | struct activation *a; | |
96 | ||
97 | a = (struct activation *)a_sp; | |
98 | a_sp += sizeof(struct activation) + sizeof(struct value *) * size; | |
99 | ||
100 | a->size = size; | |
101 | a->caller = caller; | |
102 | a->enclosing = enclosing; | |
103 | ||
104 | #ifdef DEBUG | |
105 | if (trace_activations > 1) { | |
106 | printf("[ARC] created on STACK "); | |
107 | activation_dump(a, -1); | |
108 | printf("\n"); | |
109 | } | |
110 | activations_allocated++; | |
111 | #endif | |
112 | ||
113 | return(a); | |
114 | } | |
115 | ||
116 | void | |
117 | activation_free_from_heap(struct activation *a) | |
118 | { | |
119 | int i; | |
120 | ||
121 | #ifdef DEBUG | |
122 | if (trace_activations > 1) { | |
123 | printf("[ARC] freeing from HEAP "); | |
124 | activation_dump(a, -1); | |
125 | printf("\n"); | |
126 | } | |
127 | activations_freed++; | |
128 | #endif | |
129 | ||
130 | for (i = 0; i < a->size; i++) | |
131 | value_release(VALARY(a, i)); | |
132 | ||
133 | bhuna_free(a); | |
134 | a_count--; | |
135 | } | |
136 | ||
137 | int | |
138 | activation_is_on_stack(struct activation *a) | |
139 | { | |
140 | return ((unsigned char *)a >= a_stack && | |
141 | (unsigned char *)a < (a_stack + A_STACK_SIZE)); | |
142 | } | |
143 | ||
144 | void | |
145 | activation_free_from_stack(struct activation *a) | |
146 | { | |
147 | int i; | |
148 | ||
149 | #ifdef DEBUG | |
150 | if (trace_activations > 1) { | |
151 | printf("[ARC] freeing from STACK "); | |
152 | activation_dump(a, -1); | |
153 | printf("\n"); | |
154 | } | |
155 | activations_freed++; | |
156 | #endif | |
157 | ||
158 | for (i = 0; i < a->size; i++) | |
159 | value_release(VALARY(a, i)); | |
160 | ||
161 | a_sp -= (sizeof(struct activation) + sizeof(struct value *) * a->size); | |
162 | } | |
163 | ||
164 | /*#ifndef REFCOUNTING_MACROS*/ | |
165 | struct value * | |
166 | activation_get_value(struct activation *a, int index, int upcount) | |
167 | { | |
168 | assert(a != NULL); | |
169 | for (; upcount > 0; upcount--) { | |
170 | a = a->enclosing; | |
171 | assert(a != NULL); | |
172 | } | |
173 | #ifdef DEBUG | |
174 | assert(index < a->size); | |
175 | #endif | |
176 | return(((struct value **)((char *)a + sizeof(struct activation)))[index]); | |
177 | } | |
178 | ||
179 | void | |
180 | activation_set_value(struct activation *a, int index, int upcount, | |
181 | struct value *v) | |
182 | { | |
183 | assert(a != NULL); | |
184 | for (; upcount > 0; upcount--) { | |
185 | a = a->enclosing; | |
186 | assert(a != NULL); | |
187 | } | |
188 | ||
189 | #ifdef DEBUG | |
190 | /* | |
191 | printf("set: index = %d, a->size = %d in \n", index, a->size); | |
192 | activation_dump(a, 1); | |
193 | printf("\n"); | |
194 | */ | |
195 | assert(index < a->size); | |
196 | #endif | |
197 | value_release(VALARY(a, index)); | |
198 | value_grab(v); | |
199 | VALARY(a, index) = v; | |
200 | } | |
201 | ||
202 | void | |
203 | activation_initialize_value(struct activation *a, int index, | |
204 | struct value *v) | |
205 | { | |
206 | assert(a != NULL); | |
207 | assert(index < a->size); | |
208 | value_grab(v); | |
209 | VALARY(a, index) = v; | |
210 | } | |
211 | /*#endif*/ | |
212 | ||
213 | void | |
214 | activation_dump(struct activation *a, int detail) | |
215 | { | |
216 | #ifdef DEBUG | |
217 | int i; | |
218 | ||
219 | printf("A/"); | |
220 | if (a == NULL) { | |
221 | printf("(NULL)/"); | |
222 | return; | |
223 | } | |
224 | printf("%08lx:%d", (unsigned long)a, a->size); | |
225 | ||
226 | if (detail > 0) { | |
227 | for (i = 0; i < a->size; i++) { | |
228 | printf(" "); | |
229 | if (VALARY(a, i) != NULL && VALARY(a, i)->type == VALUE_CLOSURE) { | |
230 | printf("(closure) "); | |
231 | } else { | |
232 | value_print(VALARY(a, i)); | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | if (a->enclosing != NULL) { | |
238 | printf(" --> {"); | |
239 | activation_dump(a->enclosing, 0); | |
240 | printf("}"); | |
241 | } | |
242 | if (a->caller != NULL) { | |
243 | printf(" +++> {"); | |
244 | activation_dump(a->caller, 0); | |
245 | printf("}"); | |
246 | } | |
247 | printf("/"); | |
248 | #endif | |
249 | } | |
250 | ||
251 | /* | |
252 | * Garbage collector. Not just the cheesy little reference counter, but | |
253 | * the real meat-and-potatoes mark-and-sweep. (Which we need, | |
254 | * because an activation record can contain a closure which contain | |
255 | * an activation record, and refcounts can't handle that cycle.) | |
256 | * | |
257 | * This is not particularly sophisticated; I'm more concerned with | |
258 | * correctness than performance here. | |
259 | */ | |
260 | static void activation_mark(struct activation *a); | |
261 | ||
262 | static void | |
263 | value_mark(struct value *v) | |
264 | { | |
265 | struct list *l; | |
266 | ||
267 | if (v == NULL) | |
268 | return; | |
269 | switch (v->type) { | |
270 | case VALUE_LIST: | |
271 | for (l = v->v.l; l != NULL; l = l->next) { | |
272 | value_mark(l->value); | |
273 | } | |
274 | break; | |
275 | case VALUE_CLOSURE: | |
276 | activation_mark(v->v.k->ar); | |
277 | break; | |
278 | case VALUE_DICT: | |
279 | /* XXX for each key in v->v.d, value_mark(d[k]) */ | |
280 | break; | |
281 | default: | |
282 | /* | |
283 | * No need to go through other values as they | |
284 | * are not containers. | |
285 | */ | |
286 | break; | |
287 | } | |
288 | } | |
289 | ||
290 | static void | |
291 | activation_mark(struct activation *a) | |
292 | { | |
293 | int i; | |
294 | ||
295 | if (a == NULL || a->marked) | |
296 | return; | |
297 | ||
298 | #ifdef DEBUG | |
299 | if (trace_activations > 1) { | |
300 | printf("[GC] MARKING AS REACHABLE: "); | |
301 | activation_dump(a, 0); | |
302 | printf("\n"); | |
303 | } | |
304 | #endif | |
305 | ||
306 | a->marked = 1; | |
307 | activation_mark(a->caller); | |
308 | activation_mark(a->enclosing); | |
309 | for (i = 0; i < a->size; i++) { | |
310 | value_mark(VALARY(a, i)); | |
311 | } | |
312 | } | |
313 | ||
314 | void | |
315 | activation_gc(void) | |
316 | { | |
317 | struct activation *a, *next; | |
318 | struct activation *t_head = NULL; | |
319 | ||
320 | /* | |
321 | * Mark... | |
322 | */ | |
323 | activation_mark(current_ar); | |
324 | ||
325 | /* | |
326 | * ...and sweep | |
327 | */ | |
328 | for (a = a_head; a != NULL; a = next) { | |
329 | next = a->next; | |
330 | if (a->marked) { | |
331 | a->marked = 0; | |
332 | a->next = t_head; | |
333 | t_head = a; | |
334 | } else { | |
335 | #ifdef DEBUG | |
336 | if (trace_activations > 1) { | |
337 | printf("[GC] FOUND UNREACHABLE: "); | |
338 | activation_dump(a, 0); | |
339 | printf("\n"); | |
340 | } | |
341 | #endif | |
342 | activation_free_from_heap(a); | |
343 | } | |
344 | } | |
345 | ||
346 | a_head = t_head; | |
347 | } |
0 | #define DEFAULT_GC_TRIGGER 512 | |
1 | ||
2 | struct value; | |
3 | ||
4 | /* | |
5 | * Structure of an activation record. | |
6 | * This is actually only the header; | |
7 | * the frame itself (containing local variables) | |
8 | * follows immediately in memory. | |
9 | */ | |
10 | struct activation { | |
11 | struct activation *next; /* global list of all act recs */ | |
12 | int marked; | |
13 | int size; | |
14 | struct activation *caller; /* recursively shallower activation record */ | |
15 | struct activation *enclosing; /* lexically enclosing activation record */ | |
16 | /* | |
17 | struct value *value[]; | |
18 | */ | |
19 | }; | |
20 | ||
21 | struct activation *activation_new_on_heap(int, struct activation *, struct activation *); | |
22 | struct activation *activation_new_on_stack(int, struct activation *, struct activation *); | |
23 | int activation_is_on_stack(struct activation *); | |
24 | void activation_free_from_heap(struct activation *); | |
25 | void activation_free_from_stack(struct activation *); | |
26 | ||
27 | struct value *activation_get_value(struct activation *, int, int); | |
28 | void activation_set_value(struct activation *, int, int, struct value *); | |
29 | void activation_initialize_value(struct activation *, int, struct value *); | |
30 | ||
31 | void activation_dump(struct activation *, int); | |
32 | ||
33 | void activation_gc(void); |
0 | #include <stdio.h> | |
1 | #include <stdlib.h> | |
2 | #include <string.h> | |
3 | ||
4 | #include "ast.h" | |
5 | #include "list.h" | |
6 | #include "value.h" | |
7 | #include "builtin.h" | |
8 | #include "activation.h" | |
9 | #include "vm.h" | |
10 | #include "type.h" | |
11 | #include "scan.h" | |
12 | ||
13 | #include "symbol.h" | |
14 | ||
15 | extern unsigned char program[]; | |
16 | extern int trace_type_inference; | |
17 | ||
18 | /***** constructors *****/ | |
19 | ||
20 | struct ast * | |
21 | ast_new(int type) | |
22 | { | |
23 | struct ast *a; | |
24 | ||
25 | a = malloc(sizeof(struct ast)); | |
26 | a->type = type; | |
27 | a->sc = NULL; | |
28 | a->label = NULL; | |
29 | a->datatype = NULL; | |
30 | ||
31 | return(a); | |
32 | } | |
33 | ||
34 | struct ast * | |
35 | ast_new_local(struct symbol_table *stab, struct symbol *sym) | |
36 | { | |
37 | struct ast *a; | |
38 | ||
39 | a = ast_new(AST_LOCAL); | |
40 | a->u.local.index = sym->index; | |
41 | a->u.local.upcount = stab->level - sym->in->level; | |
42 | a->u.local.sym = sym; | |
43 | a->datatype = sym->type; | |
44 | ||
45 | #ifdef DEBUG | |
46 | if (trace_type_inference) { | |
47 | printf("(new-local)*****\n"); | |
48 | printf("type is: "); | |
49 | type_print(stdout, a->datatype); | |
50 | printf("\n*******\n"); | |
51 | } | |
52 | #endif | |
53 | ||
54 | return(a); | |
55 | } | |
56 | ||
57 | struct ast * | |
58 | ast_new_value(struct value *v, struct type *t) | |
59 | { | |
60 | struct ast *a; | |
61 | ||
62 | a = ast_new(AST_VALUE); | |
63 | value_grab(v); | |
64 | a->u.value.value = v; | |
65 | a->datatype = t; | |
66 | ||
67 | #ifdef DEBUG | |
68 | if (trace_type_inference) { | |
69 | printf("(value)*****\n"); | |
70 | printf("type is: "); | |
71 | type_print(stdout, a->datatype); | |
72 | printf("\n*******\n"); | |
73 | } | |
74 | #endif | |
75 | ||
76 | return(a); | |
77 | } | |
78 | ||
79 | struct ast * | |
80 | ast_new_builtin(struct scan_st *sc, struct builtin *bi, struct ast *right) | |
81 | { | |
82 | struct ast *a; | |
83 | struct type *t; | |
84 | int unify = 0; | |
85 | ||
86 | t = bi->ty(); | |
87 | type_ensure_routine(t); | |
88 | ||
89 | #ifdef DEBUG | |
90 | if (trace_type_inference) { | |
91 | printf("(builtin `%s`)*****\n", bi->name); | |
92 | printf("type of args is: "); | |
93 | type_print(stdout, right->datatype); | |
94 | printf("\ntype of builtin is: "); | |
95 | type_print(stdout, t); | |
96 | } | |
97 | #endif | |
98 | ||
99 | unify = type_unify_crit(sc, | |
100 | type_representative(t)->t.closure.domain, | |
101 | right->datatype); | |
102 | ||
103 | #ifdef DEBUG | |
104 | if (trace_type_inference) { | |
105 | printf("\nthese unify? --> %d <--", unify); | |
106 | printf("\n****\n"); | |
107 | } | |
108 | #endif | |
109 | ||
110 | /* | |
111 | * Fold constants. | |
112 | */ | |
113 | if (bi->is_pure && ast_is_constant(right)) { | |
114 | struct value *v = NULL; | |
115 | struct activation *ar; | |
116 | struct ast *g; | |
117 | int i = 0; | |
118 | int varity; | |
119 | ||
120 | if (bi->arity == -1) { | |
121 | varity = ast_count_args(right); | |
122 | } else { | |
123 | varity = bi->arity; | |
124 | } | |
125 | ||
126 | if (unify) { | |
127 | ar = activation_new_on_stack(varity, NULL, NULL); | |
128 | for (g = right, i = 0; | |
129 | g != NULL && g->type == AST_ARG && i < varity; | |
130 | g = g->u.arg.right, i++) { | |
131 | if (g->u.arg.left != NULL) | |
132 | activation_initialize_value(ar, i, | |
133 | g->u.arg.left->u.value.value); | |
134 | } | |
135 | bi->fn(ar, &v); | |
136 | activation_free_from_stack(ar); | |
137 | } else { | |
138 | a = NULL; | |
139 | } | |
140 | ||
141 | a = ast_new_value(v, type_representative(t)->t.closure.range); | |
142 | value_release(v); | |
143 | ||
144 | return(a); | |
145 | } | |
146 | ||
147 | a = ast_new(AST_BUILTIN); | |
148 | ||
149 | a->u.builtin.bi = bi; | |
150 | a->u.builtin.right = right; | |
151 | a->datatype = type_representative(t)->t.closure.range; | |
152 | ||
153 | return(a); | |
154 | } | |
155 | ||
156 | struct ast * | |
157 | ast_new_apply(struct scan_st *sc, struct ast *fn, struct ast *args, int is_pure) | |
158 | { | |
159 | struct ast *a; | |
160 | int unify; | |
161 | ||
162 | a = ast_new(AST_APPLY); | |
163 | a->u.apply.left = fn; | |
164 | a->u.apply.right = args; | |
165 | a->u.apply.is_pure = is_pure; | |
166 | ||
167 | type_ensure_routine(fn->datatype); | |
168 | ||
169 | #ifdef DEBUG | |
170 | if (trace_type_inference) { | |
171 | printf("(apply)*****\n"); | |
172 | printf("type of args is: "); | |
173 | if (args == NULL) printf("N/A"); else type_print(stdout, args->datatype); | |
174 | printf("\ntype of closure is: "); | |
175 | type_print(stdout, fn->datatype); | |
176 | } | |
177 | #endif | |
178 | ||
179 | if (args == NULL) { | |
180 | unify = type_unify_crit(sc, | |
181 | type_representative(fn->datatype)->t.closure.domain, | |
182 | type_new(TYPE_VOID)); /* XXX need not be new */ | |
183 | } else { | |
184 | unify = type_unify_crit(sc, | |
185 | type_representative(fn->datatype)->t.closure.domain, | |
186 | args->datatype); | |
187 | } | |
188 | ||
189 | #ifdef DEBUG | |
190 | if (trace_type_inference) { | |
191 | printf("\nthese unify? --> %d <--", unify); | |
192 | printf("\n****\n"); | |
193 | } | |
194 | #endif | |
195 | ||
196 | a->datatype = type_representative(fn->datatype)->t.closure.range; | |
197 | ||
198 | return(a); | |
199 | } | |
200 | ||
201 | struct ast * | |
202 | ast_new_arg(struct ast *left, struct ast *right) | |
203 | { | |
204 | struct ast *a; | |
205 | ||
206 | a = ast_new(AST_ARG); | |
207 | a->u.arg.left = left; | |
208 | a->u.arg.right = right; | |
209 | if (a->u.arg.right == NULL) { | |
210 | a->datatype = a->u.arg.left->datatype; | |
211 | } else { | |
212 | a->datatype = type_new_arg( | |
213 | a->u.arg.left->datatype, | |
214 | a->u.arg.right->datatype); | |
215 | } | |
216 | return(a); | |
217 | } | |
218 | ||
219 | struct ast * | |
220 | ast_new_routine(int arity, int locals, int cc, struct ast *body) | |
221 | { | |
222 | struct ast *a; | |
223 | ||
224 | a = ast_new(AST_ROUTINE); | |
225 | a->u.routine.arity = arity; | |
226 | a->u.routine.locals = locals; | |
227 | a->u.routine.cc = cc; | |
228 | a->u.routine.body = body; | |
229 | ||
230 | a->datatype = a->u.routine.body->datatype; | |
231 | ||
232 | #ifdef DEBUG | |
233 | if (trace_type_inference) { | |
234 | printf("(routine)*****\n"); | |
235 | printf("type is: "); | |
236 | type_print(stdout, a->datatype); | |
237 | printf("\n****\n"); | |
238 | } | |
239 | #endif | |
240 | ||
241 | return(a); | |
242 | } | |
243 | ||
244 | struct ast * | |
245 | ast_new_statement(struct ast *left, struct ast *right) | |
246 | { | |
247 | struct ast *a; | |
248 | ||
249 | if (left == NULL && right == NULL) | |
250 | return(NULL); | |
251 | if (left == NULL) | |
252 | return(right); | |
253 | if (right == NULL) | |
254 | return(left); | |
255 | ||
256 | a = ast_new(AST_STATEMENT); | |
257 | a->u.statement.left = left; | |
258 | a->u.statement.right = right; | |
259 | /* XXX check that a->u.statement.left->datatype is VOID ?? */ | |
260 | a->datatype = a->u.statement.right->datatype; | |
261 | /* haha... */ | |
262 | /* | |
263 | a->datatype = type_new_set(a->u.statement.left->datatype, | |
264 | a->u.statement.right->datatype); | |
265 | */ | |
266 | ||
267 | #ifdef DEBUG | |
268 | if (trace_type_inference) { | |
269 | printf("(statement)*****\n"); | |
270 | printf("type is: "); | |
271 | type_print(stdout, a->datatype); | |
272 | printf("\n****\n"); | |
273 | } | |
274 | #endif | |
275 | ||
276 | return(a); | |
277 | } | |
278 | ||
279 | struct ast * | |
280 | ast_new_assignment(struct scan_st *sc, struct ast *left, struct ast *right) | |
281 | { | |
282 | struct ast *a; | |
283 | int unify; | |
284 | ||
285 | /* | |
286 | * Do some 'self-repairing' in the case of syntax errors that | |
287 | * generate a corrupt AST (e.g. Foo = <eof>) | |
288 | */ | |
289 | if (right == NULL) | |
290 | return(left); | |
291 | ||
292 | a = ast_new(AST_ASSIGNMENT); | |
293 | a->u.assignment.left = left; | |
294 | a->u.assignment.right = right; | |
295 | ||
296 | unify = type_unify_crit(sc, left->datatype, right->datatype); | |
297 | ||
298 | #ifdef DEBUG | |
299 | if (trace_type_inference) { | |
300 | printf("(assign)*****\n"); | |
301 | printf("type of LHS is: "); | |
302 | type_print(stdout, left->datatype); | |
303 | printf("\ntype of RHS is: "); | |
304 | type_print(stdout, right->datatype); | |
305 | printf("\nthese unify? --> %d <--", unify); | |
306 | printf("\ntype of LHS is now: "); | |
307 | type_print(stdout, left->datatype); | |
308 | printf("\n****\n"); | |
309 | } | |
310 | #endif | |
311 | ||
312 | return(a); | |
313 | } | |
314 | ||
315 | struct ast * | |
316 | ast_new_conditional(struct scan_st *sc, struct ast *test, struct ast *yes, struct ast *no) | |
317 | { | |
318 | struct ast *a; | |
319 | int unify; | |
320 | ||
321 | a = ast_new(AST_CONDITIONAL); | |
322 | a->u.conditional.test = test; | |
323 | a->u.conditional.yes = yes; | |
324 | a->u.conditional.no = no; | |
325 | /* check that a->u.conditional.test is BOOLEAN */ | |
326 | ||
327 | /* XXX need not be new boolean - reuse an old one */ | |
328 | unify = type_unify_crit(sc, test->datatype, type_new(TYPE_BOOLEAN)); | |
329 | ||
330 | #ifdef DEBUG | |
331 | if (trace_type_inference) { | |
332 | printf("(if)*****\n"); | |
333 | printf("type of YES is: "); | |
334 | type_print(stdout, yes->datatype); | |
335 | printf("\ntype of NO is: "); | |
336 | type_print(stdout, no->datatype); | |
337 | } | |
338 | #endif | |
339 | ||
340 | /* XXX check that a->u.conditional.yes is VOID */ | |
341 | /* XXX check that a->u.conditional.no is VOID */ | |
342 | ||
343 | /* actually, either of these can be VOID, in which case, pick the other */ | |
344 | /* unify = type_unify_crit(sc, yes->datatype, no->datatype); */ | |
345 | /* haha */ | |
346 | a->datatype = type_new_set(a->u.conditional.yes->datatype, | |
347 | a->u.conditional.no->datatype); | |
348 | ||
349 | #ifdef DEBUG | |
350 | if (trace_type_inference) { | |
351 | printf("\nresult type is: "); | |
352 | type_print(stdout, a->datatype); | |
353 | printf("\n****\n"); | |
354 | } | |
355 | #endif | |
356 | ||
357 | return(a); | |
358 | } | |
359 | ||
360 | struct ast * | |
361 | ast_new_while_loop(struct scan_st *sc, struct ast *test, struct ast *body) | |
362 | { | |
363 | struct ast *a; | |
364 | int unify; | |
365 | ||
366 | a = malloc(sizeof(struct ast)); | |
367 | a->type = AST_WHILE_LOOP; | |
368 | ||
369 | a->u.while_loop.test = test; | |
370 | a->u.while_loop.body = body; | |
371 | /* XXX need not be new boolean - reuse an old one */ | |
372 | unify = type_unify_crit(sc, test->datatype, type_new(TYPE_BOOLEAN)); | |
373 | ||
374 | /* XXX check that a->u.while_loop.body is VOID */ | |
375 | /* a->datatype = type_new(TYPE_VOID); */ | |
376 | a->datatype = body->datatype; | |
377 | ||
378 | return(a); | |
379 | } | |
380 | ||
381 | struct ast * | |
382 | ast_new_retr(struct ast *body) | |
383 | { | |
384 | struct ast *a; | |
385 | ||
386 | a = ast_new(AST_RETR); | |
387 | a->u.retr.body = body; | |
388 | /* XXX check against other return statements in same function... somehow... */ | |
389 | a->datatype = a->u.retr.body->datatype; | |
390 | ||
391 | #ifdef DEBUG | |
392 | if (trace_type_inference) { | |
393 | printf("(retr)*****\n"); | |
394 | printf("type is: "); | |
395 | type_print(stdout, a->datatype); | |
396 | printf("\n****\n"); | |
397 | } | |
398 | #endif | |
399 | ||
400 | return(a); | |
401 | } | |
402 | ||
403 | /*** DESTRUCTOR ***/ | |
404 | ||
405 | void | |
406 | ast_free(struct ast *a) | |
407 | { | |
408 | if (a == NULL) { | |
409 | return; | |
410 | } | |
411 | switch (a->type) { | |
412 | case AST_LOCAL: | |
413 | break; | |
414 | case AST_VALUE: | |
415 | value_release(a->u.value.value); | |
416 | break; | |
417 | case AST_BUILTIN: | |
418 | ast_free(a->u.builtin.right); | |
419 | break; | |
420 | case AST_APPLY: | |
421 | ast_free(a->u.apply.left); | |
422 | ast_free(a->u.apply.right); | |
423 | break; | |
424 | case AST_ARG: | |
425 | ast_free(a->u.arg.left); | |
426 | ast_free(a->u.arg.right); | |
427 | break; | |
428 | case AST_ROUTINE: | |
429 | ast_free(a->u.routine.body); | |
430 | break; | |
431 | case AST_STATEMENT: | |
432 | ast_free(a->u.statement.left); | |
433 | ast_free(a->u.statement.right); | |
434 | break; | |
435 | case AST_ASSIGNMENT: | |
436 | ast_free(a->u.assignment.left); | |
437 | ast_free(a->u.assignment.right); | |
438 | break; | |
439 | case AST_CONDITIONAL: | |
440 | ast_free(a->u.conditional.test); | |
441 | ast_free(a->u.conditional.yes); | |
442 | ast_free(a->u.conditional.no); | |
443 | break; | |
444 | case AST_WHILE_LOOP: | |
445 | ast_free(a->u.while_loop.test); | |
446 | ast_free(a->u.while_loop.body); | |
447 | break; | |
448 | case AST_RETR: | |
449 | ast_free(a->u.retr.body); | |
450 | break; | |
451 | } | |
452 | if (a->sc != NULL) | |
453 | scan_close(a->sc); | |
454 | free(a); | |
455 | } | |
456 | ||
457 | /*** PREDICATES &c. ***/ | |
458 | ||
459 | int | |
460 | ast_is_constant(struct ast *a) | |
461 | { | |
462 | if (a == NULL) | |
463 | return(1); | |
464 | switch (a->type) { | |
465 | case AST_VALUE: | |
466 | return(1); | |
467 | case AST_ARG: | |
468 | return(ast_is_constant(a->u.arg.left) && | |
469 | ast_is_constant(a->u.arg.right)); | |
470 | } | |
471 | return(0); | |
472 | } | |
473 | ||
474 | int | |
475 | ast_count_args(struct ast *a) | |
476 | { | |
477 | int ac; | |
478 | ||
479 | for (ac = 0; a != NULL && a->type == AST_ARG; a = a->u.arg.right, ac++) | |
480 | ; | |
481 | ||
482 | return(ac); | |
483 | } | |
484 | ||
485 | /*** DEBUGGING ***/ | |
486 | ||
487 | char * | |
488 | ast_name(struct ast *a) | |
489 | { | |
490 | #ifdef DEBUG | |
491 | if (a == NULL) | |
492 | return("(null)"); | |
493 | switch (a->type) { | |
494 | case AST_LOCAL: | |
495 | return("AST_LOCAL"); | |
496 | case AST_VALUE: | |
497 | return("AST_VALUE"); | |
498 | case AST_BUILTIN: | |
499 | return("AST_BUILTIN"); | |
500 | case AST_APPLY: | |
501 | return("AST_APPLY"); | |
502 | case AST_ARG: | |
503 | return("AST_ARG"); | |
504 | case AST_ROUTINE: | |
505 | return("AST_ROUTINE"); | |
506 | case AST_STATEMENT: | |
507 | return("AST_STATEMENT"); | |
508 | case AST_ASSIGNMENT: | |
509 | return("AST_ASSIGNMENT"); | |
510 | case AST_CONDITIONAL: | |
511 | return("AST_CONDITIONAL"); | |
512 | case AST_WHILE_LOOP: | |
513 | return("AST_WHILE_LOOP"); | |
514 | case AST_RETR: | |
515 | return("AST_RETR"); | |
516 | } | |
517 | #endif | |
518 | return("AST_UNKNOWN??!?"); | |
519 | } | |
520 | ||
521 | void | |
522 | ast_dump(struct ast *a, int indent) | |
523 | { | |
524 | #ifdef DEBUG | |
525 | int i; | |
526 | ||
527 | if (a == NULL) { | |
528 | return; | |
529 | } | |
530 | for (i = 0; i < indent; i++) printf(" "); | |
531 | if (a->label != NULL) { | |
532 | printf("@#%d -> ", a->label - (vm_label_t)program); | |
533 | } | |
534 | printf(ast_name(a)); | |
535 | printf("="); | |
536 | type_print(stdout, a->datatype); | |
537 | switch (a->type) { | |
538 | case AST_LOCAL: | |
539 | printf("(%d,%d)=", a->u.local.index, a->u.local.upcount); | |
540 | if (a->u.local.sym != NULL) | |
541 | symbol_dump(a->u.local.sym, 0); | |
542 | printf("\n"); | |
543 | break; | |
544 | case AST_VALUE: | |
545 | printf("("); | |
546 | value_print(a->u.value.value); | |
547 | printf(")\n"); | |
548 | break; | |
549 | case AST_BUILTIN: | |
550 | printf("`%s`{\n", a->u.builtin.bi->name); | |
551 | ast_dump(a->u.builtin.right, indent + 1); | |
552 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
553 | break; | |
554 | case AST_APPLY: | |
555 | printf("{\n"); | |
556 | ast_dump(a->u.apply.left, indent + 1); | |
557 | ast_dump(a->u.apply.right, indent + 1); | |
558 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
559 | break; | |
560 | case AST_ARG: | |
561 | printf("{\n"); | |
562 | ast_dump(a->u.arg.left, indent + 1); | |
563 | ast_dump(a->u.arg.right, indent + 1); | |
564 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
565 | break; | |
566 | case AST_ROUTINE: | |
567 | printf("/%d (contains %d) {\n", | |
568 | a->u.routine.arity, a->u.routine.cc); | |
569 | ast_dump(a->u.routine.body, indent + 1); | |
570 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
571 | break; | |
572 | case AST_STATEMENT: | |
573 | printf("{\n"); | |
574 | ast_dump(a->u.statement.left, indent + 1); | |
575 | ast_dump(a->u.statement.right, indent + 1); | |
576 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
577 | break; | |
578 | case AST_ASSIGNMENT: | |
579 | printf("{\n"); | |
580 | ast_dump(a->u.assignment.left, indent + 1); | |
581 | ast_dump(a->u.assignment.right, indent + 1); | |
582 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
583 | break; | |
584 | case AST_CONDITIONAL: | |
585 | printf("{\n"); | |
586 | ast_dump(a->u.conditional.test, indent + 1); | |
587 | ast_dump(a->u.conditional.yes, indent + 1); | |
588 | if (a->u.conditional.no != NULL) | |
589 | ast_dump(a->u.conditional.no, indent + 1); | |
590 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
591 | break; | |
592 | case AST_WHILE_LOOP: | |
593 | printf("{\n"); | |
594 | ast_dump(a->u.while_loop.test, indent + 1); | |
595 | ast_dump(a->u.while_loop.body, indent + 1); | |
596 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
597 | break; | |
598 | case AST_RETR: | |
599 | printf("{\n"); | |
600 | ast_dump(a->u.retr.body, indent + 1); | |
601 | for (i = 0; i < indent; i++) printf(" "); printf("}\n"); | |
602 | break; | |
603 | } | |
604 | #endif | |
605 | } |
0 | #ifndef __AST_H_ | |
1 | #define __AST_H_ | |
2 | ||
3 | #include "vm.h" | |
4 | ||
5 | struct value; | |
6 | struct builtin; | |
7 | struct type; | |
8 | struct symbol; | |
9 | struct symbol_table; | |
10 | struct scan_st; | |
11 | ||
12 | struct ast_local { | |
13 | int index; | |
14 | int upcount; | |
15 | struct symbol *sym; | |
16 | }; | |
17 | ||
18 | struct ast_value { | |
19 | struct value *value; | |
20 | }; | |
21 | ||
22 | struct ast_builtin { | |
23 | struct builtin *bi; | |
24 | struct ast *right; /* ISA arg */ | |
25 | }; | |
26 | ||
27 | struct ast_apply { | |
28 | struct ast *left; /* ISA var(/...?) (fn/cmd) */ | |
29 | struct ast *right; /* ISA arg */ | |
30 | int is_pure; | |
31 | }; | |
32 | ||
33 | struct ast_arg { | |
34 | struct ast *left; /* ISA arg/apply/var */ | |
35 | struct ast *right; /* ISA arg/apply/var */ | |
36 | }; | |
37 | ||
38 | struct ast_routine { | |
39 | int arity; /* takes this many arguments */ | |
40 | int locals;/* has this many local variables */ | |
41 | int cc; /* contains this many closures */ | |
42 | struct ast *body; | |
43 | }; | |
44 | ||
45 | struct ast_statement { | |
46 | struct ast *left; /* ISA statement/apply */ | |
47 | struct ast *right; /* ISA statement/apply */ | |
48 | }; | |
49 | ||
50 | struct ast_assignment { | |
51 | struct ast *left; /* ISA var */ | |
52 | struct ast *right; /* ISA apply/var */ | |
53 | }; | |
54 | ||
55 | struct ast_conditional { | |
56 | struct ast *test; /* ISA apply/var */ | |
57 | struct ast *yes; /* ISA statement/apply */ | |
58 | struct ast *no; /* ISA statement/apply/NULL */ | |
59 | /*int index;*/ /* temp var in act rec */ | |
60 | }; | |
61 | ||
62 | struct ast_while_loop { | |
63 | struct ast *test; /* ISA apply/var */ | |
64 | struct ast *body; /* ISA statement/apply */ | |
65 | }; | |
66 | ||
67 | struct ast_retr { | |
68 | struct ast *body; /* ISA apply/var */ | |
69 | }; | |
70 | ||
71 | #define AST_LOCAL 1 | |
72 | #define AST_VALUE 2 | |
73 | #define AST_BUILTIN 3 | |
74 | #define AST_APPLY 4 | |
75 | #define AST_ARG 5 | |
76 | #define AST_ROUTINE 6 | |
77 | #define AST_STATEMENT 7 | |
78 | #define AST_ASSIGNMENT 8 | |
79 | #define AST_CONDITIONAL 9 | |
80 | #define AST_WHILE_LOOP 10 | |
81 | #define AST_RETR 11 | |
82 | ||
83 | union ast_union { | |
84 | struct ast_local local; | |
85 | struct ast_value value; | |
86 | struct ast_builtin builtin; | |
87 | struct ast_apply apply; | |
88 | struct ast_arg arg; | |
89 | struct ast_routine routine; | |
90 | struct ast_statement statement; | |
91 | struct ast_assignment assignment; | |
92 | struct ast_conditional conditional; | |
93 | struct ast_while_loop while_loop; | |
94 | struct ast_retr retr; | |
95 | }; | |
96 | ||
97 | struct ast { | |
98 | int type; | |
99 | struct scan_st *sc; | |
100 | struct type *datatype; | |
101 | vm_label_t label; | |
102 | union ast_union u; | |
103 | }; | |
104 | ||
105 | struct ast *ast_new_local(struct symbol_table *, struct symbol *); | |
106 | struct ast *ast_new_value(struct value *, struct type *); | |
107 | struct ast *ast_new_builtin(struct scan_st *, struct builtin *, struct ast *); | |
108 | struct ast *ast_new_apply(struct scan_st *, struct ast *, struct ast *, int); | |
109 | struct ast *ast_new_arg(struct ast *, struct ast *); | |
110 | struct ast *ast_new_routine(int, int, int, struct ast *); | |
111 | struct ast *ast_new_statement(struct ast *, struct ast *); | |
112 | struct ast *ast_new_assignment(struct scan_st *, struct ast *, struct ast *); | |
113 | struct ast *ast_new_conditional(struct scan_st *, struct ast *, struct ast *, struct ast *); | |
114 | struct ast *ast_new_while_loop(struct scan_st *, struct ast *, struct ast *); | |
115 | struct ast *ast_new_retr(struct ast *); | |
116 | void ast_free(struct ast *); | |
117 | ||
118 | int ast_is_constant(struct ast *); | |
119 | int ast_count_args(struct ast *); | |
120 | ||
121 | void ast_dump(struct ast *, int); | |
122 | char *ast_name(struct ast *); | |
123 | ||
124 | void ast_eval_init(void); | |
125 | void ast_eval(struct ast *, struct value **); | |
126 | ||
127 | #endif /* !__AST_H_ */ |
0 | #include <string.h> | |
1 | #include <stdlib.h> | |
2 | ||
3 | #include "mem.h" | |
4 | #include "atom.h" | |
5 | ||
6 | static struct atom_entry *atom_entry_head = NULL; | |
7 | static int next_atom = 0; | |
8 | ||
9 | int | |
10 | atom_resolve(char *lexeme) | |
11 | { | |
12 | struct atom_entry *ae; | |
13 | ||
14 | /* find lexeme in atom table */ | |
15 | for (ae = atom_entry_head; ae != NULL; ae = ae->next) { | |
16 | if (strcmp(ae->lexeme, lexeme) == 0) | |
17 | return(ae->atom); | |
18 | } | |
19 | /* create new atom */ | |
20 | ae = bhuna_malloc(sizeof(struct atom_entry)); | |
21 | ae->next = atom_entry_head; | |
22 | ae->lexeme = strdup(lexeme); | |
23 | ae->atom = next_atom++; | |
24 | atom_entry_head = ae; | |
25 | ||
26 | return(ae->atom); | |
27 | } |
0 | #ifndef __ATOM_H_ | |
1 | #define __ATOM_H_ | |
2 | ||
3 | struct atom_entry { | |
4 | struct atom_entry *next; | |
5 | char *lexeme; | |
6 | int atom; | |
7 | }; | |
8 | ||
9 | int atom_resolve(char *); | |
10 | ||
11 | #endif /* !__ATOM_H_ */ |
0 | /* | |
1 | * Copyright (c) 2004 The DragonFly Project. All rights reserved. | |
2 | * | |
3 | * This code is derived from software contributed to The DragonFly Project | |
4 | * by Chris Pressey <cpressey@catseye.mine.nu>. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in | |
14 | * the documentation and/or other materials provided with the | |
15 | * distribution. | |
16 | * 3. Neither the name of The DragonFly Project nor the names of its | |
17 | * contributors may be used to endorse or promote products derived | |
18 | * from this software without specific, prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
24 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * extbuf.c | |
36 | * $Id: buffer.c,v 1.1 2004/07/21 19:52:35 cpressey Exp $ | |
37 | * Routines to manipulate extensible buffers. | |
38 | * | |
39 | * Aura buffers are buffers that attempt to automatically expand | |
40 | * when more data is written to them than they can initially hold. | |
41 | * In addition, each extensible buffer contains a cursor from which | |
42 | * its contents may be incrementally scanned. | |
43 | */ | |
44 | ||
45 | #include <err.h> | |
46 | #include <stdarg.h> | |
47 | #include <stdio.h> | |
48 | #include <stdlib.h> | |
49 | #include <string.h> | |
50 | #include <sysexits.h> | |
51 | ||
52 | #include "buffer.h" | |
53 | ||
54 | /* | |
55 | * Create a new extensible buffer with the given initial size. | |
56 | */ | |
57 | struct aura_buffer * | |
58 | aura_buffer_new(size_t size) | |
59 | { | |
60 | struct aura_buffer *e; | |
61 | ||
62 | e = malloc(sizeof(struct aura_buffer)); | |
63 | ||
64 | e->len = 0; | |
65 | e->size = size; | |
66 | e->pos = 0; | |
67 | ||
68 | e->buf = malloc(size); | |
69 | e->buf[0] = '\0'; | |
70 | ||
71 | return(e); | |
72 | } | |
73 | ||
74 | /* | |
75 | * Deallocate the memory used for an extensible buffer. | |
76 | */ | |
77 | void | |
78 | aura_buffer_free(struct aura_buffer *e) | |
79 | { | |
80 | if (e != NULL) { | |
81 | if (e->buf != NULL) | |
82 | free(e->buf); | |
83 | free(e); | |
84 | } | |
85 | } | |
86 | ||
87 | /* | |
88 | * Return the underlying (static) buffer of an extensible buffer. | |
89 | * | |
90 | * NOTE that you should NEVER cache the returned pointer anywhere, | |
91 | * as any further manipulation of the extensible buffer may cause | |
92 | * it to be invalidated. | |
93 | * | |
94 | * ALSO NOTE that the buffer may contain embedded NULs, but will | |
95 | * also be guaranteed to be NUL-terminated. | |
96 | */ | |
97 | char * | |
98 | aura_buffer_buf(struct aura_buffer *e) | |
99 | { | |
100 | return(e->buf); | |
101 | } | |
102 | ||
103 | /* | |
104 | * Return the current length of the extensible buffer. | |
105 | */ | |
106 | size_t | |
107 | aura_buffer_len(struct aura_buffer *e) | |
108 | { | |
109 | return(e->len); | |
110 | } | |
111 | ||
112 | /* | |
113 | * Return the current size of the extensible buffer. This is how | |
114 | * big it's length may grow to before expanded. | |
115 | */ | |
116 | size_t | |
117 | aura_buffer_size(struct aura_buffer *e) | |
118 | { | |
119 | return(e->size); | |
120 | } | |
121 | ||
122 | /* | |
123 | * Ensure that an extensible buffer's size is at least the given | |
124 | * size. If it is not, it will be internally grown to that size. | |
125 | * This does not affect the contents of the buffer in any way. | |
126 | */ | |
127 | void | |
128 | aura_buffer_ensure_size(struct aura_buffer *e, size_t size) | |
129 | { | |
130 | if (e->size >= size) return; | |
131 | e->size = size; | |
132 | if ((e->buf = realloc(e->buf, e->size)) == NULL) { | |
133 | err(EX_UNAVAILABLE, "realloc()"); | |
134 | } | |
135 | } | |
136 | ||
137 | /* | |
138 | * Set the contents of an extensible buffer from a regular (char *) | |
139 | * buffer. The extensible buffer will grow if needed. Any existing | |
140 | * contents of the extensible buffer are destroyed in this operation. | |
141 | * Note that, because this requires that the length of the | |
142 | * regular buffer be specified, it may safely contain NUL bytes. | |
143 | */ | |
144 | void | |
145 | aura_buffer_set(struct aura_buffer *e, char *buf, size_t length) | |
146 | { | |
147 | while ((length + 1) > e->size) { | |
148 | e->size *= 2; | |
149 | } | |
150 | if ((e->buf = realloc(e->buf, e->size)) == NULL) { | |
151 | err(EX_UNAVAILABLE, "realloc()"); | |
152 | } | |
153 | memcpy(e->buf, buf, length); | |
154 | e->len = length; | |
155 | e->buf[e->len] = '\0'; | |
156 | } | |
157 | ||
158 | /* | |
159 | * Append the contents of a regular buffer to the end of the existing | |
160 | * contents of an extensible buffer. The extensible buffer will grow | |
161 | * if needed. Note that, because this requires that the length of the | |
162 | * regular buffer be specified, it may safely contain NUL bytes. | |
163 | */ | |
164 | void | |
165 | aura_buffer_append(struct aura_buffer *e, char *buf, size_t length) | |
166 | { | |
167 | while (e->len + (length + 1) > e->size) { | |
168 | e->size *= 2; | |
169 | } | |
170 | if ((e->buf = realloc(e->buf, e->size)) == NULL) { | |
171 | err(EX_UNAVAILABLE, "realloc()"); | |
172 | } | |
173 | memcpy(e->buf + e->len, buf, length); | |
174 | e->len += length; | |
175 | e->buf[e->len] = '\0'; | |
176 | } | |
177 | ||
178 | /* | |
179 | * Set the contents of an extensible buffer from an ASCIIZ string. | |
180 | * This is identical to aura_buffer_set except that the length need not | |
181 | * be specified, and the ASCIIZ string may not contain embedded NUL's. | |
182 | */ | |
183 | void | |
184 | aura_buffer_cpy(struct aura_buffer *e, char *s) | |
185 | { | |
186 | aura_buffer_set(e, s, strlen(s)); | |
187 | } | |
188 | ||
189 | /* | |
190 | * Append the contents of an ASCIIZ string to an extensible buffer. | |
191 | * This is identical to aura_buffer_append except that the length need not | |
192 | * be specified, and the ASCIIZ string may not contain embedded NUL's. | |
193 | */ | |
194 | void | |
195 | aura_buffer_cat(struct aura_buffer *e, char *s) | |
196 | { | |
197 | aura_buffer_append(e, s, strlen(s)); | |
198 | } | |
199 | ||
200 | /* | |
201 | * Append the entire contents of a text file to an extensible buffer. | |
202 | */ | |
203 | int | |
204 | aura_buffer_cat_file(struct aura_buffer *e, char *fmt, ...) | |
205 | { | |
206 | va_list args; | |
207 | char *filename, line[1024]; | |
208 | FILE *f; | |
209 | ||
210 | va_start(args, fmt); | |
211 | vasprintf(&filename, fmt, args); | |
212 | va_end(args); | |
213 | ||
214 | if ((f = fopen(filename, "r")) == NULL) | |
215 | return(0); | |
216 | ||
217 | free(filename); | |
218 | ||
219 | while (fgets(line, 1023, f) != NULL) { | |
220 | aura_buffer_cat(e, line); | |
221 | } | |
222 | ||
223 | fclose(f); | |
224 | ||
225 | return(1); | |
226 | } | |
227 | ||
228 | /* | |
229 | * Append the entire output of a shell command to an extensible buffer. | |
230 | */ | |
231 | int | |
232 | aura_buffer_cat_pipe(struct aura_buffer *e, char *fmt, ...) | |
233 | { | |
234 | va_list args; | |
235 | char *command, line[1024]; | |
236 | FILE *p; | |
237 | ||
238 | va_start(args, fmt); | |
239 | vasprintf(&command, fmt, args); | |
240 | va_end(args); | |
241 | ||
242 | if ((p = popen(command, "r")) == NULL) | |
243 | return(0); | |
244 | ||
245 | free(command); | |
246 | ||
247 | while (fgets(line, 1023, p) != NULL) { | |
248 | aura_buffer_cat(e, line); | |
249 | } | |
250 | ||
251 | pclose(p); | |
252 | ||
253 | return(1); | |
254 | } | |
255 | ||
256 | /*** CURSORED FUNCTIONS ***/ | |
257 | ||
258 | /* | |
259 | * Note that the cursor can be anywhere from the first character to | |
260 | * one position _beyond_ the last character in the buffer. | |
261 | */ | |
262 | ||
263 | int | |
264 | aura_buffer_seek(struct aura_buffer *e, size_t pos) | |
265 | { | |
266 | if (pos <= e->size) { | |
267 | e->pos = pos; | |
268 | return(1); | |
269 | } else { | |
270 | return(0); | |
271 | } | |
272 | } | |
273 | ||
274 | size_t | |
275 | aura_buffer_tell(struct aura_buffer *e) | |
276 | { | |
277 | return(e->pos); | |
278 | } | |
279 | ||
280 | int | |
281 | aura_buffer_eof(struct aura_buffer *e) | |
282 | { | |
283 | return(e->pos >= e->size); | |
284 | } | |
285 | ||
286 | char | |
287 | aura_buffer_peek_char(struct aura_buffer *e) | |
288 | { | |
289 | return(e->buf[e->pos]); | |
290 | } | |
291 | ||
292 | char | |
293 | aura_buffer_scan_char(struct aura_buffer *e) | |
294 | { | |
295 | return(e->buf[e->pos++]); | |
296 | } | |
297 | ||
298 | int | |
299 | aura_buffer_compare(struct aura_buffer *e, char *s) | |
300 | { | |
301 | int i, pos; | |
302 | ||
303 | for (i = 0, pos = e->pos; s[i] != '\0' && pos < e->size; i++, pos++) { | |
304 | if (e->buf[pos] != s[i]) | |
305 | return(0); | |
306 | } | |
307 | ||
308 | if (pos <= e->size) { | |
309 | return(pos); | |
310 | } else { | |
311 | return(0); | |
312 | } | |
313 | } | |
314 | ||
315 | int | |
316 | aura_buffer_expect(struct aura_buffer *e, char *s) | |
317 | { | |
318 | int pos; | |
319 | ||
320 | if ((pos = aura_buffer_compare(e, s)) > 0) { | |
321 | e->pos = pos; | |
322 | return(1); | |
323 | } else { | |
324 | return(0); | |
325 | } | |
326 | } | |
327 | ||
328 | void | |
329 | aura_buffer_push(struct aura_buffer *e, void *src, size_t len) | |
330 | { | |
331 | aura_buffer_ensure_size(e, e->pos + len); | |
332 | memcpy(e->buf + e->pos, src, len); | |
333 | e->pos += len; | |
334 | } | |
335 | ||
336 | int | |
337 | aura_buffer_pop(struct aura_buffer *e, void *dest, size_t len) | |
338 | { | |
339 | if (e->pos - len > 0) { | |
340 | e->pos -= len; | |
341 | memcpy(dest, e->buf + e->pos, len); | |
342 | return(1); | |
343 | } else { | |
344 | return(0); | |
345 | } | |
346 | } |
0 | /* | |
1 | * Copyright (c) 2004 The DragonFly Project. All rights reserved. | |
2 | * | |
3 | * This code is derived from software contributed to The DragonFly Project | |
4 | * by Chris Pressey <cpressey@catseye.mine.nu>. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in | |
14 | * the documentation and/or other materials provided with the | |
15 | * distribution. | |
16 | * 3. Neither the name of The DragonFly Project nor the names of its | |
17 | * contributors may be used to endorse or promote products derived | |
18 | * from this software without specific, prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
24 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * buffer.h | |
36 | * $Id: buffer.h,v 1.1 2004/07/21 19:52:35 cpressey Exp $ | |
37 | */ | |
38 | ||
39 | #ifndef __AURA_BUFFER_H_ | |
40 | #define __AURA_BUFFER_H_ | |
41 | ||
42 | #include <stdlib.h> | |
43 | ||
44 | struct aura_buffer { | |
45 | char *buf; | |
46 | size_t len; | |
47 | size_t size; | |
48 | size_t pos; | |
49 | }; | |
50 | ||
51 | struct aura_buffer *aura_buffer_new(size_t); | |
52 | void aura_buffer_free(struct aura_buffer *); | |
53 | char *aura_buffer_buf(struct aura_buffer *); | |
54 | size_t aura_buffer_len(struct aura_buffer *); | |
55 | size_t aura_buffer_size(struct aura_buffer *); | |
56 | ||
57 | void aura_buffer_ensure_size(struct aura_buffer *, size_t); | |
58 | void aura_buffer_set(struct aura_buffer *, char *, size_t); | |
59 | void aura_buffer_append(struct aura_buffer *, char *, size_t); | |
60 | ||
61 | void aura_buffer_cpy(struct aura_buffer *, char *); | |
62 | void aura_buffer_cat(struct aura_buffer *, char *); | |
63 | int aura_buffer_cat_file(struct aura_buffer *, char *, ...); | |
64 | int aura_buffer_cat_pipe(struct aura_buffer *, char *, ...); | |
65 | ||
66 | int aura_buffer_seek(struct aura_buffer *, size_t); | |
67 | size_t aura_buffer_tell(struct aura_buffer *); | |
68 | int aura_buffer_eof(struct aura_buffer *); | |
69 | char aura_buffer_peek_char(struct aura_buffer *); | |
70 | char aura_buffer_scan_char(struct aura_buffer *); | |
71 | int aura_buffer_compare(struct aura_buffer *, char *); | |
72 | int aura_buffer_expect(struct aura_buffer *, char *); | |
73 | ||
74 | void aura_buffer_push(struct aura_buffer *, void *, size_t); | |
75 | int aura_buffer_pop(struct aura_buffer *, void *, size_t); | |
76 | ||
77 | #endif /* !__AURA_BUFFER_H_ */ |
0 | #include <stdio.h> | |
1 | #include <stdlib.h> | |
2 | ||
3 | #include "builtin.h" | |
4 | #include "value.h" | |
5 | #include "list.h" | |
6 | #include "dict.h" | |
7 | #include "closure.h" | |
8 | #include "activation.h" | |
9 | #include "type.h" | |
10 | ||
11 | /* | |
12 | * Built-in operations. | |
13 | */ | |
14 | ||
15 | struct builtin builtins[] = { | |
16 | {"Print", builtin_print, btype_print, -1, 0, 1, 0}, | |
17 | {"!", builtin_not, btype_unary_logic, 1, 1, 1, 1}, | |
18 | {"&", builtin_and, btype_binary_logic, 2, 1, 1, 2}, | |
19 | {"|", builtin_or, btype_binary_logic, 2, 1, 1, 3}, | |
20 | {"=", builtin_equ, btype_compare, 2, 1, 1, 4}, | |
21 | {"!=", builtin_neq, btype_compare, 2, 1, 1, 5}, | |
22 | {">", builtin_gt, btype_compare, 2, 1, 1, 6}, | |
23 | {"<", builtin_lt, btype_compare, 2, 1, 1, 7}, | |
24 | {">=", builtin_gte, btype_compare, 2, 1, 1, 8}, | |
25 | {"<=", builtin_lte, btype_compare, 2, 1, 1, 9}, | |
26 | {"+", builtin_add, btype_arith, 2, 1, 1, 10}, | |
27 | {"-", builtin_sub, btype_arith, 2, 1, 1, 11}, | |
28 | {"*", builtin_mul, btype_arith, 2, 1, 1, 12}, | |
29 | {"/", builtin_div, btype_arith, 2, 1, 1, 13}, | |
30 | {"%", builtin_mod, btype_arith, 2, 1, 1, 14}, | |
31 | {"List", builtin_list, btype_list, -1, 1, 1, 15}, | |
32 | {"Fetch", builtin_fetch, btype_fetch, 2, 1, 1, 16}, | |
33 | {"Store", builtin_store, btype_store, 3, 0, 1, 17}, | |
34 | {"Dict", builtin_dict, btype_dict, -1, 1, 1, 18}, | |
35 | {NULL, NULL, NULL, 0, 0, 0, 19} | |
36 | }; | |
37 | ||
38 | void | |
39 | builtin_print(struct activation *ar, struct value **q) | |
40 | { | |
41 | int i; | |
42 | /*struct list *l;*/ | |
43 | struct value *v = NULL; | |
44 | ||
45 | for (i = 0; i < ar->size; i++) { | |
46 | v = activation_get_value(ar, i, 0); | |
47 | if (v == NULL) { | |
48 | printf("(null)"); | |
49 | continue; | |
50 | } | |
51 | ||
52 | switch (v->type) { | |
53 | case VALUE_INTEGER: | |
54 | printf("%d", v->v.i); | |
55 | break; | |
56 | case VALUE_BOOLEAN: | |
57 | printf("%s", v->v.b ? "true" : "false"); | |
58 | break; | |
59 | case VALUE_STRING: | |
60 | printf("%s", v->v.s); | |
61 | break; | |
62 | case VALUE_LIST: | |
63 | /* | |
64 | printf("["); | |
65 | for (l = v->v.l; l != NULL; l = l->next) { | |
66 | */ | |
67 | ||
68 | list_dump(v->v.l); | |
69 | break; | |
70 | case VALUE_ERROR: | |
71 | printf("#ERR<%s>", v->v.e); | |
72 | break; | |
73 | case VALUE_BUILTIN: | |
74 | printf("#BIF<%08lx>", (unsigned long)v->v.bi); | |
75 | break; | |
76 | case VALUE_CLOSURE: | |
77 | closure_dump(v->v.k); | |
78 | break; | |
79 | case VALUE_DICT: | |
80 | dict_dump(v->v.d); | |
81 | break; | |
82 | default: | |
83 | printf("???unknown(%d)???", v->type); | |
84 | break; | |
85 | } | |
86 | } | |
87 | ||
88 | value_set_from_value(q, v); | |
89 | } | |
90 | ||
91 | /*** logical ***/ | |
92 | ||
93 | void | |
94 | builtin_not(struct activation *ar, struct value **v) | |
95 | { | |
96 | struct value *q = activation_get_value(ar, 0, 0); | |
97 | ||
98 | if (q->type == VALUE_BOOLEAN) { | |
99 | return(value_set_boolean(v, !q->v.b)); | |
100 | } else { | |
101 | return(value_set_error(v, "type mismatch")); | |
102 | } | |
103 | } | |
104 | ||
105 | void | |
106 | builtin_and(struct activation *ar, struct value **v) | |
107 | { | |
108 | struct value *l = activation_get_value(ar, 0, 0); | |
109 | struct value *r = activation_get_value(ar, 1, 0); | |
110 | ||
111 | if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) { | |
112 | return(value_set_boolean(v, l->v.b && r->v.b)); | |
113 | } else { | |
114 | return(value_set_error(v, "type mismatch")); | |
115 | } | |
116 | } | |
117 | ||
118 | void | |
119 | builtin_or(struct activation *ar, struct value **v) | |
120 | { | |
121 | struct value *l = activation_get_value(ar, 0, 0); | |
122 | struct value *r = activation_get_value(ar, 1, 0); | |
123 | ||
124 | if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) { | |
125 | return(value_set_boolean(v, l->v.b || r->v.b)); | |
126 | } else { | |
127 | return(value_set_error(v, "type mismatch")); | |
128 | } | |
129 | } | |
130 | ||
131 | /*** comparison ***/ | |
132 | ||
133 | void | |
134 | builtin_equ(struct activation *ar, struct value **v) | |
135 | { | |
136 | struct value *l = activation_get_value(ar, 0, 0); | |
137 | struct value *r = activation_get_value(ar, 1, 0); | |
138 | ||
139 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
140 | return(value_set_boolean(v, l->v.i == r->v.i)); | |
141 | } else { | |
142 | return(value_set_error(v, "type mismatch")); | |
143 | } | |
144 | } | |
145 | ||
146 | void | |
147 | builtin_neq(struct activation *ar, struct value **v) | |
148 | { | |
149 | struct value *l = activation_get_value(ar, 0, 0); | |
150 | struct value *r = activation_get_value(ar, 1, 0); | |
151 | ||
152 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
153 | return(value_set_boolean(v, l->v.i != r->v.i)); | |
154 | } else { | |
155 | return(value_set_error(v, "type mismatch")); | |
156 | } | |
157 | } | |
158 | ||
159 | void | |
160 | builtin_gt(struct activation *ar, struct value **v) | |
161 | { | |
162 | struct value *l = activation_get_value(ar, 0, 0); | |
163 | struct value *r = activation_get_value(ar, 1, 0); | |
164 | ||
165 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
166 | return(value_set_boolean(v, l->v.i > r->v.i)); | |
167 | } else { | |
168 | return(value_set_error(v, "type mismatch")); | |
169 | } | |
170 | } | |
171 | ||
172 | void | |
173 | builtin_lt(struct activation *ar, struct value **v) | |
174 | { | |
175 | struct value *l = activation_get_value(ar, 0, 0); | |
176 | struct value *r = activation_get_value(ar, 1, 0); | |
177 | ||
178 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
179 | return(value_set_boolean(v, l->v.i < r->v.i)); | |
180 | } else { | |
181 | return(value_set_error(v, "type mismatch")); | |
182 | } | |
183 | } | |
184 | ||
185 | void | |
186 | builtin_gte(struct activation *ar, struct value **v) | |
187 | { | |
188 | struct value *l = activation_get_value(ar, 0, 0); | |
189 | struct value *r = activation_get_value(ar, 1, 0); | |
190 | ||
191 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
192 | return(value_set_boolean(v, l->v.i >= r->v.i)); | |
193 | } else { | |
194 | return(value_set_error(v, "type mismatch")); | |
195 | } | |
196 | } | |
197 | ||
198 | void | |
199 | builtin_lte(struct activation *ar, struct value **v) | |
200 | { | |
201 | struct value *l = activation_get_value(ar, 0, 0); | |
202 | struct value *r = activation_get_value(ar, 1, 0); | |
203 | ||
204 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
205 | return(value_set_boolean(v, l->v.i <= r->v.i)); | |
206 | } else { | |
207 | return(value_set_error(v, "type mismatch")); | |
208 | } | |
209 | } | |
210 | ||
211 | /*** arithmetic ***/ | |
212 | ||
213 | void | |
214 | builtin_add(struct activation *ar, struct value **v) | |
215 | { | |
216 | struct value *l = activation_get_value(ar, 0, 0); | |
217 | struct value *r = activation_get_value(ar, 1, 0); | |
218 | ||
219 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
220 | return(value_set_integer(v, l->v.i + r->v.i)); | |
221 | } else { | |
222 | return(value_set_error(v, "type mismatch")); | |
223 | } | |
224 | } | |
225 | ||
226 | void | |
227 | builtin_mul(struct activation *ar, struct value **v) | |
228 | { | |
229 | struct value *l = activation_get_value(ar, 0, 0); | |
230 | struct value *r = activation_get_value(ar, 1, 0); | |
231 | ||
232 | #if 0 | |
233 | printf("IN MUL, L = "); | |
234 | value_print(l); | |
235 | printf(" R = "); | |
236 | value_print(r); | |
237 | printf("\n"); | |
238 | #endif | |
239 | ||
240 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
241 | return(value_set_integer(v, l->v.i * r->v.i)); | |
242 | } else { | |
243 | return(value_set_error(v, "type mismatch")); | |
244 | } | |
245 | } | |
246 | ||
247 | void | |
248 | builtin_sub(struct activation *ar, struct value **v) | |
249 | { | |
250 | struct value *l = activation_get_value(ar, 0, 0); | |
251 | struct value *r = activation_get_value(ar, 1, 0); | |
252 | ||
253 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
254 | return(value_set_integer(v, l->v.i - r->v.i)); | |
255 | } else { | |
256 | return(value_set_error(v, "type mismatch")); | |
257 | } | |
258 | } | |
259 | ||
260 | void | |
261 | builtin_div(struct activation *ar, struct value **v) | |
262 | { | |
263 | struct value *l = activation_get_value(ar, 0, 0); | |
264 | struct value *r = activation_get_value(ar, 1, 0); | |
265 | ||
266 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
267 | if (r->v.i == 0) | |
268 | return(value_set_error(v, "division by zero")); | |
269 | else | |
270 | return(value_set_integer(v, l->v.i / r->v.i)); | |
271 | } else { | |
272 | return(value_set_error(v, "type mismatch")); | |
273 | } | |
274 | } | |
275 | ||
276 | void | |
277 | builtin_mod(struct activation *ar, struct value **v) | |
278 | { | |
279 | struct value *l = activation_get_value(ar, 0, 0); | |
280 | struct value *r = activation_get_value(ar, 1, 0); | |
281 | ||
282 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
283 | if (r->v.i == 0) | |
284 | return(value_set_error(v, "modulo by zero")); | |
285 | else | |
286 | return(value_set_integer(v, l->v.i % r->v.i)); | |
287 | } else { | |
288 | return(value_set_error(v, "type mismatch")); | |
289 | } | |
290 | } | |
291 | ||
292 | /*** list ***/ | |
293 | ||
294 | void | |
295 | builtin_list(struct activation *ar, struct value **v) | |
296 | { | |
297 | int i; | |
298 | struct value *x = NULL; | |
299 | ||
300 | value_set_list(v); | |
301 | ||
302 | for (i = ar->size - 1; i >= 0; i--) { | |
303 | x = activation_get_value(ar, i, 0); | |
304 | value_list_append(v, x); | |
305 | value_release(x); | |
306 | } | |
307 | } | |
308 | ||
309 | void | |
310 | builtin_fetch(struct activation *ar, struct value **v) | |
311 | { | |
312 | struct value *l = activation_get_value(ar, 0, 0); | |
313 | struct value *r = activation_get_value(ar, 1, 0); | |
314 | struct value *q; | |
315 | int count; | |
316 | struct list *li; | |
317 | ||
318 | if (l->type == VALUE_CLOSURE && r->type == VALUE_INTEGER) { | |
319 | int i = r->v.i - 1; | |
320 | /* | |
321 | * This is _EVIL_! | |
322 | */ | |
323 | if (i >= 0 && i < l->v.k->ar->size) { | |
324 | q = activation_get_value(l->v.k->ar, i, 0); | |
325 | value_set_from_value(v, q); | |
326 | } else { | |
327 | value_set_error(v, "out of bounds"); | |
328 | } | |
329 | } else if (l->type == VALUE_DICT) { | |
330 | q = dict_fetch(l->v.d, r); | |
331 | value_set_from_value(v, q); | |
332 | value_release(q); | |
333 | } else if (l->type == VALUE_LIST && r->type == VALUE_INTEGER) { | |
334 | li = l->v.l; | |
335 | for (count = 1; li != NULL && count < r->v.i; count++) | |
336 | li = li->next; | |
337 | if (li == NULL) | |
338 | return(value_set_error(v, "out of bounds")); | |
339 | else { | |
340 | value_set_from_value(v, li->value); | |
341 | } | |
342 | } else { | |
343 | return(value_set_error(v, "type mismatch")); | |
344 | } | |
345 | } | |
346 | ||
347 | void | |
348 | builtin_store(struct activation *ar, struct value **v) | |
349 | { | |
350 | struct value *d = activation_get_value(ar, 0, 0); | |
351 | struct value *i = activation_get_value(ar, 1, 0); | |
352 | struct value *p = activation_get_value(ar, 2, 0); | |
353 | int count; | |
354 | struct list *li; | |
355 | ||
356 | if (d->type == VALUE_DICT) { | |
357 | dict_store(d->v.d, i, p); | |
358 | value_set_from_value(v, d); | |
359 | } else if (d->type == VALUE_LIST && i->type == VALUE_INTEGER) { | |
360 | li = d->v.l; | |
361 | for (count = 1; li != NULL && count < i->v.i; count++) | |
362 | li = li->next; | |
363 | if (li == NULL) | |
364 | value_set_error(v, "no such element"); | |
365 | else { | |
366 | value_set_from_value(&li->value, p); | |
367 | value_set_from_value(v, d); | |
368 | } | |
369 | } else { | |
370 | value_set_error(v, "type mismatch"); | |
371 | } | |
372 | } | |
373 | ||
374 | void | |
375 | builtin_dict(struct activation *ar, struct value **v) | |
376 | { | |
377 | int i; | |
378 | struct value *key = NULL, *val = NULL; | |
379 | ||
380 | value_set_dict(v); | |
381 | ||
382 | if (ar->size % 2 != 0) { | |
383 | value_set_error(v, "number of argument must be even"); | |
384 | } else { | |
385 | for (i = 0; i < ar->size; i += 2) { | |
386 | key = activation_get_value(ar, i, 0); | |
387 | val = activation_get_value(ar, i + 1, 0); | |
388 | value_dict_store(v, key, val); | |
389 | value_release(key); | |
390 | value_release(val); | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | struct type * | |
396 | btype_print(void) | |
397 | { | |
398 | return( | |
399 | type_new_closure( | |
400 | type_new_var(1), | |
401 | type_new(TYPE_VOID) | |
402 | ) | |
403 | ); | |
404 | } | |
405 | ||
406 | struct type * | |
407 | btype_unary_logic(void) | |
408 | { | |
409 | return( | |
410 | type_new_closure( | |
411 | type_new(TYPE_BOOLEAN), | |
412 | type_new(TYPE_BOOLEAN) | |
413 | ) | |
414 | ); | |
415 | } | |
416 | ||
417 | struct type * | |
418 | btype_binary_logic(void) | |
419 | { | |
420 | return( | |
421 | type_new_closure( | |
422 | type_new_arg(type_new(TYPE_BOOLEAN), type_new(TYPE_BOOLEAN)), | |
423 | type_new(TYPE_BOOLEAN) | |
424 | ) | |
425 | ); | |
426 | } | |
427 | ||
428 | struct type * | |
429 | btype_compare(void) | |
430 | { | |
431 | return( | |
432 | type_new_closure( | |
433 | type_new_arg(type_new(TYPE_INTEGER), type_new(TYPE_INTEGER)), | |
434 | type_new(TYPE_BOOLEAN) | |
435 | ) | |
436 | ); | |
437 | } | |
438 | ||
439 | struct type * | |
440 | btype_arith(void) | |
441 | { | |
442 | return( | |
443 | type_new_closure( | |
444 | type_new_arg(type_new(TYPE_INTEGER), type_new(TYPE_INTEGER)), | |
445 | type_new(TYPE_INTEGER) | |
446 | ) | |
447 | ); | |
448 | } | |
449 | ||
450 | struct type * | |
451 | btype_list(void) | |
452 | { | |
453 | return( | |
454 | type_new_closure( | |
455 | type_new_var(2), | |
456 | type_new_list(type_new(TYPE_INTEGER)) | |
457 | ) | |
458 | ); | |
459 | } | |
460 | ||
461 | struct type * | |
462 | btype_fetch(void) | |
463 | { | |
464 | return( | |
465 | type_new_closure( | |
466 | type_new_arg(type_new_var(5), type_new(TYPE_INTEGER)), | |
467 | type_new_var(5) | |
468 | ) | |
469 | ); | |
470 | } | |
471 | ||
472 | struct type * | |
473 | btype_store(void) | |
474 | { | |
475 | return( | |
476 | type_new_closure( | |
477 | type_new_arg( | |
478 | type_new_var(6), | |
479 | type_new_arg(type_new_var(7), type_new_var(8)) | |
480 | ), | |
481 | type_new(TYPE_VOID) | |
482 | ) | |
483 | ); | |
484 | } | |
485 | ||
486 | struct type * | |
487 | btype_dict(void) | |
488 | { | |
489 | return(NULL); | |
490 | } |
0 | #ifndef __BUILTIN_H_ | |
1 | #define __BUILTIN_H_ | |
2 | ||
3 | struct value; | |
4 | struct activation; | |
5 | struct type; | |
6 | ||
7 | struct builtin { | |
8 | char *name; | |
9 | void (*fn)(struct activation *, struct value **); | |
10 | struct type *(*ty)(void); | |
11 | int arity; | |
12 | int is_pure; | |
13 | int is_const; | |
14 | int index; | |
15 | }; | |
16 | ||
17 | #define INDEX_BUILTIN_PRINT 0 | |
18 | #define INDEX_BUILTIN_NOT 1 | |
19 | #define INDEX_BUILTIN_AND 2 | |
20 | #define INDEX_BUILTIN_OR 3 | |
21 | #define INDEX_BUILTIN_EQU 4 | |
22 | #define INDEX_BUILTIN_NEQ 5 | |
23 | #define INDEX_BUILTIN_GT 6 | |
24 | #define INDEX_BUILTIN_LT 7 | |
25 | #define INDEX_BUILTIN_GTE 8 | |
26 | #define INDEX_BUILTIN_LTE 9 | |
27 | #define INDEX_BUILTIN_ADD 10 | |
28 | #define INDEX_BUILTIN_SUB 11 | |
29 | #define INDEX_BUILTIN_MUL 12 | |
30 | #define INDEX_BUILTIN_DIV 13 | |
31 | #define INDEX_BUILTIN_MOD 14 | |
32 | #define INDEX_BUILTIN_LIST 15 | |
33 | #define INDEX_BUILTIN_FETCH 16 | |
34 | #define INDEX_BUILTIN_STORE 17 | |
35 | #define INDEX_BUILTIN_DICT 18 | |
36 | ||
37 | #define INDEX_BUILTIN_LAST 127 | |
38 | ||
39 | extern struct builtin builtins[]; | |
40 | ||
41 | void builtin_print(struct activation *, struct value **); | |
42 | ||
43 | void builtin_not(struct activation *, struct value **); | |
44 | void builtin_and(struct activation *, struct value **); | |
45 | void builtin_or(struct activation *, struct value **); | |
46 | ||
47 | void builtin_equ(struct activation *, struct value **); | |
48 | void builtin_neq(struct activation *, struct value **); | |
49 | void builtin_gt(struct activation *, struct value **); | |
50 | void builtin_lt(struct activation *, struct value **); | |
51 | void builtin_gte(struct activation *, struct value **); | |
52 | void builtin_lte(struct activation *, struct value **); | |
53 | ||
54 | void builtin_add(struct activation *, struct value **); | |
55 | void builtin_mul(struct activation *, struct value **); | |
56 | void builtin_sub(struct activation *, struct value **); | |
57 | void builtin_div(struct activation *, struct value **); | |
58 | void builtin_mod(struct activation *, struct value **); | |
59 | ||
60 | void builtin_list(struct activation *, struct value **); | |
61 | void builtin_fetch(struct activation *, struct value **); | |
62 | void builtin_store(struct activation *, struct value **); | |
63 | ||
64 | void builtin_dict(struct activation *, struct value **); | |
65 | ||
66 | struct type *btype_print(void); | |
67 | struct type *btype_unary_logic(void); | |
68 | struct type *btype_binary_logic(void); | |
69 | struct type *btype_compare(void); | |
70 | struct type *btype_arith(void); | |
71 | struct type *btype_list(void); | |
72 | struct type *btype_fetch(void); | |
73 | struct type *btype_store(void); | |
74 | struct type *btype_dict(void); | |
75 | ||
76 | #endif |
0 | #include <assert.h> | |
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | ||
4 | #include "mem.h" | |
5 | #include "closure.h" | |
6 | #include "symbol.h" | |
7 | #include "ast.h" | |
8 | #include "activation.h" | |
9 | #include "vm.h" | |
10 | ||
11 | #include "type.h" | |
12 | ||
13 | struct closure * | |
14 | closure_new(struct ast *a, struct activation *ar) | |
15 | { | |
16 | struct closure *c; | |
17 | ||
18 | c = bhuna_malloc(sizeof(struct closure)); | |
19 | ||
20 | c->ast = a; | |
21 | c->ar = ar; | |
22 | ||
23 | return(c); | |
24 | } | |
25 | ||
26 | void | |
27 | closure_free(struct closure *c) | |
28 | { | |
29 | bhuna_free(c); | |
30 | } | |
31 | ||
32 | void | |
33 | closure_dump(struct closure *c) | |
34 | { | |
35 | #ifdef DEBUG | |
36 | printf("closure{"); | |
37 | activation_dump(c->ar, 1); | |
38 | ast_dump(c->ast, 1); | |
39 | printf("}"); | |
40 | #endif | |
41 | } |
0 | #ifndef __CLOSURE_H_ | |
1 | #define __CLOSURE_H_ | |
2 | ||
3 | #include "vm.h" | |
4 | ||
5 | struct activation; | |
6 | struct ast; | |
7 | ||
8 | struct closure { | |
9 | struct ast *ast; | |
10 | struct activation *ar; /* env in which we were created */ | |
11 | }; | |
12 | ||
13 | struct closure *closure_new(struct ast *, struct activation *); | |
14 | void closure_free(struct closure *); | |
15 | void closure_dump(struct closure *); | |
16 | ||
17 | #endif |
0 | /* | |
1 | * Copyright (c) 2004 The DragonFly Project. All rights reserved. | |
2 | * | |
3 | * This code is derived from software contributed to The DragonFly Project | |
4 | * by Chris Pressey <cpressey@catseye.mine.nu>. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in | |
14 | * the documentation and/or other materials provided with the | |
15 | * distribution. | |
16 | * 3. Neither the name of The DragonFly Project nor the names of its | |
17 | * contributors may be used to endorse or promote products derived | |
18 | * from this software without specific, prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
24 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * dict.c | |
36 | * $Id$ | |
37 | * Routines to manipulate Bhuna dictionaries. | |
38 | */ | |
39 | ||
40 | #include <assert.h> | |
41 | #include <stdlib.h> | |
42 | #include <string.h> | |
43 | #include <stdio.h> | |
44 | ||
45 | #include "mem.h" | |
46 | ||
47 | #include "dict.h" | |
48 | #include "value.h" | |
49 | ||
50 | /*** CONSTRUCTOR ***/ | |
51 | ||
52 | /* | |
53 | * Create a new dictionary. | |
54 | */ | |
55 | struct dict * | |
56 | dict_new(void) | |
57 | { | |
58 | struct dict *d; | |
59 | int i; | |
60 | ||
61 | d = bhuna_malloc(sizeof(struct dict)); | |
62 | d->num_buckets = 31; | |
63 | d->bucket = bhuna_malloc(sizeof(struct chain *) * d->num_buckets); | |
64 | for (i = 0; i < d->num_buckets; i++) { | |
65 | d->bucket[i] = NULL; | |
66 | } | |
67 | d->cursor = NULL; | |
68 | d->cur_bucket = 0; | |
69 | ||
70 | return(d); | |
71 | } | |
72 | ||
73 | static struct chain * | |
74 | chain_dup(struct chain *f) | |
75 | { | |
76 | struct chain *c, *n, *p = NULL, *h = NULL; | |
77 | ||
78 | for (c = f; c != NULL; c = c->next) { | |
79 | n = bhuna_malloc(sizeof(struct chain)); | |
80 | ||
81 | n->next = NULL; | |
82 | value_grab(c->key); | |
83 | n->key = c->key; | |
84 | value_grab(c->value); | |
85 | n->value = c->value; | |
86 | ||
87 | if (h == NULL) | |
88 | h = n; | |
89 | else | |
90 | p->next = n; | |
91 | ||
92 | p = n; | |
93 | } | |
94 | ||
95 | return(h); | |
96 | } | |
97 | ||
98 | struct dict * | |
99 | dict_dup(struct dict *f) | |
100 | { | |
101 | struct dict *d; | |
102 | int i; | |
103 | ||
104 | d = bhuna_malloc(sizeof(struct dict)); | |
105 | d->num_buckets = 31; | |
106 | d->bucket = bhuna_malloc(sizeof(struct chain *) * d->num_buckets); | |
107 | for (i = 0; i < d->num_buckets; i++) { | |
108 | d->bucket[i] = chain_dup(f->bucket[i]); | |
109 | } | |
110 | d->cursor = NULL; /* hmmm... dup'ing this would take trickery. */ | |
111 | d->cur_bucket = 0; | |
112 | ||
113 | return(d); | |
114 | } | |
115 | ||
116 | /*** DESTRUCTORS ***/ | |
117 | ||
118 | static void | |
119 | chain_free(struct chain *c) | |
120 | { | |
121 | assert(c != NULL); | |
122 | ||
123 | value_release(c->key); | |
124 | value_release(c->value); | |
125 | ||
126 | bhuna_free(c); | |
127 | } | |
128 | ||
129 | void | |
130 | dict_free(struct dict *d) | |
131 | { | |
132 | struct chain *c; | |
133 | size_t bucket_no; | |
134 | ||
135 | for (bucket_no = 0; bucket_no < d->num_buckets; bucket_no++) { | |
136 | c = d->bucket[bucket_no]; | |
137 | while (c != NULL) { | |
138 | d->bucket[bucket_no] = c->next; | |
139 | chain_free(c); | |
140 | c = d->bucket[bucket_no]; | |
141 | } | |
142 | } | |
143 | bhuna_free(d); | |
144 | } | |
145 | ||
146 | /*** UTILITIES ***/ | |
147 | ||
148 | /* | |
149 | * Hash function, taken from "Compilers: Principles, Techniques, and Tools" | |
150 | * by Aho, Sethi, & Ullman (a.k.a. "The Dragon Book", 2nd edition.) | |
151 | */ | |
152 | static size_t | |
153 | hashpjw(struct value *key, size_t table_size) { | |
154 | char *p; | |
155 | unsigned long int h = 0, g; | |
156 | ||
157 | /* | |
158 | * XXX ecks ecks ecks XXX | |
159 | * This is naff... for certain values this will work. | |
160 | * For others, it won't... | |
161 | */ | |
162 | if (key->type == VALUE_INTEGER || | |
163 | key->type == VALUE_BOOLEAN || | |
164 | key->type == VALUE_ATOM) { | |
165 | for (p = (char *)key; p - (char *)key < sizeof(int); p++) { | |
166 | h = (h << 4) + (*p); | |
167 | if ((g = h & 0xf0000000)) | |
168 | h = (h ^ (g >> 24)) ^ g; | |
169 | } | |
170 | } else { | |
171 | assert("key no good" == NULL); | |
172 | } | |
173 | ||
174 | return(h % table_size); | |
175 | } | |
176 | ||
177 | /* | |
178 | * Create a new bucket (not called directly by client code.) | |
179 | */ | |
180 | static struct chain * | |
181 | chain_new(struct value *key, struct value *value) | |
182 | { | |
183 | struct chain *c; | |
184 | ||
185 | c = bhuna_malloc(sizeof(struct chain)); | |
186 | ||
187 | c->next = NULL; | |
188 | c->key = key; | |
189 | c->value = value; | |
190 | ||
191 | return(c); | |
192 | } | |
193 | ||
194 | /* | |
195 | * Locate the bucket number a particular key would be located in, and the | |
196 | * chain link itself if such a key exists (or NULL if it could not be found.) | |
197 | */ | |
198 | static void | |
199 | dict_locate(struct dict *d, struct value *key, | |
200 | size_t *b_index, struct chain **c) | |
201 | { | |
202 | *b_index = hashpjw(key, d->num_buckets); | |
203 | for (*c = d->bucket[*b_index]; *c != NULL; *c = (*c)->next) { | |
204 | if (value_equal(key, (*c)->key)) | |
205 | break; | |
206 | } | |
207 | } | |
208 | ||
209 | /*** OPERATIONS ***/ | |
210 | ||
211 | /* | |
212 | * Retrieve a value from a dictionary, given its key. | |
213 | */ | |
214 | struct value * | |
215 | dict_fetch(struct dict *d, struct value *k) | |
216 | { | |
217 | struct chain *c; | |
218 | size_t i; | |
219 | ||
220 | dict_locate(d, k, &i, &c); | |
221 | if (c != NULL) { | |
222 | value_grab(c->value); | |
223 | return(c->value); | |
224 | } else { | |
225 | return(NULL); | |
226 | } | |
227 | } | |
228 | ||
229 | /* | |
230 | * Insert a value into a dictionary. | |
231 | */ | |
232 | void | |
233 | dict_store(struct dict *d, struct value *k, struct value *v) | |
234 | { | |
235 | struct chain *c; | |
236 | size_t i; | |
237 | ||
238 | dict_locate(d, k, &i, &c); | |
239 | if (c == NULL) { | |
240 | /* Chain does not exist, add a new one. */ | |
241 | value_grab(k); | |
242 | value_grab(v); | |
243 | c = chain_new(k, v); | |
244 | c->next = d->bucket[i]; | |
245 | d->bucket[i] = c; | |
246 | } else { | |
247 | /* Chain already exists, replace the value. */ | |
248 | value_release(c->value); | |
249 | value_grab(v); | |
250 | c->value = v; | |
251 | } | |
252 | } | |
253 | ||
254 | int | |
255 | dict_exists(struct dict *d, struct value *key) | |
256 | { | |
257 | struct value *v; | |
258 | ||
259 | v = dict_fetch(d, key); | |
260 | return(v != NULL); | |
261 | } | |
262 | ||
263 | /* | |
264 | * Finds the next bucket with data in it. | |
265 | * If d->cursor == NULL after this, there is no more data. | |
266 | */ | |
267 | static void | |
268 | dict_advance(struct dict *d) | |
269 | { | |
270 | while (d->cursor == NULL) { | |
271 | if (d->cur_bucket == d->num_buckets - 1) { | |
272 | /* We're at eof. Do nothing. */ | |
273 | break; | |
274 | } else { | |
275 | d->cur_bucket++; | |
276 | d->cursor = d->bucket[d->cur_bucket]; | |
277 | } | |
278 | } | |
279 | } | |
280 | ||
281 | void | |
282 | dict_rewind(struct dict *d) | |
283 | { | |
284 | d->cur_bucket = 0; | |
285 | d->cursor = d->bucket[d->cur_bucket]; | |
286 | dict_advance(d); | |
287 | } | |
288 | ||
289 | int | |
290 | dict_eof(struct dict *d) | |
291 | { | |
292 | return(d->cursor == NULL); | |
293 | } | |
294 | ||
295 | struct value * | |
296 | dict_getkey(struct dict *d) | |
297 | { | |
298 | if (d->cursor == NULL) { | |
299 | return(NULL); | |
300 | } else { | |
301 | /* XXX grab? */ | |
302 | return(d->cursor->key); | |
303 | } | |
304 | } | |
305 | ||
306 | void | |
307 | dict_next(struct dict *d) | |
308 | { | |
309 | if (d->cursor != NULL) | |
310 | d->cursor = d->cursor->next; | |
311 | dict_advance(d); | |
312 | } | |
313 | ||
314 | size_t | |
315 | dict_size(struct dict *d) | |
316 | { | |
317 | struct chain *c; | |
318 | int bucket_no; | |
319 | size_t count = 0; | |
320 | ||
321 | for (bucket_no = 0; bucket_no < d->num_buckets; bucket_no++) { | |
322 | for (c = d->bucket[bucket_no]; c != NULL; c = c->next) | |
323 | count++; | |
324 | } | |
325 | ||
326 | return(count); | |
327 | } | |
328 | ||
329 | /*** debugging ***/ | |
330 | ||
331 | void | |
332 | dict_dump(struct dict *d) | |
333 | { | |
334 | #ifdef DEBUG | |
335 | printf("dict[%08lx]", (unsigned long)d); | |
336 | #endif | |
337 | } |
0 | /* | |
1 | * Copyright (c) 2004 The DragonFly Project. All rights reserved. | |
2 | * | |
3 | * This code is derived from software contributed to The DragonFly Project | |
4 | * by Chris Pressey <cpressey@catseye.mine.nu>. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in | |
14 | * the documentation and/or other materials provided with the | |
15 | * distribution. | |
16 | * 3. Neither the name of The DragonFly Project nor the names of its | |
17 | * contributors may be used to endorse or promote products derived | |
18 | * from this software without specific, prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
24 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * dict.c | |
36 | * $Id$ | |
37 | * Routines to manipulate Bhuna dictionaries. | |
38 | */ | |
39 | ||
40 | #ifndef __DICT_H_ | |
41 | #define __DICT_H_ | |
42 | ||
43 | struct value; | |
44 | ||
45 | struct dict { | |
46 | struct chain **bucket; | |
47 | struct chain *cursor; | |
48 | int cur_bucket; | |
49 | int num_buckets; | |
50 | }; | |
51 | ||
52 | struct chain { | |
53 | struct chain *next; | |
54 | struct value *key; | |
55 | struct value *value; | |
56 | }; | |
57 | ||
58 | struct dict *dict_new(void); | |
59 | struct dict *dict_dup(struct dict *); | |
60 | void dict_free(struct dict *); | |
61 | ||
62 | struct value *dict_fetch(struct dict *, struct value *); | |
63 | int dict_exists(struct dict *, struct value *); | |
64 | void dict_store(struct dict *, struct value *, struct value *); | |
65 | ||
66 | void dict_rewind(struct dict *); | |
67 | int dict_eof(struct dict *); | |
68 | struct value *dict_getkey(struct dict *); | |
69 | void dict_next(struct dict *); | |
70 | ||
71 | size_t dict_size(struct dict *); | |
72 | ||
73 | void dict_dump(struct dict *); | |
74 | ||
75 | #endif /* !__DICT_H_ */ |
0 | CFLAGS+=-I../lib | |
1 | ||
2 | .include "../Makefile.inc" | |
3 | ||
4 | all: bhuna | |
5 | ||
6 | bhuna: main.o | |
7 | gcc main.o -L../lib -lbhuna -o bhuna | |
8 | ||
9 | main.o: main.c | |
10 | gcc $(CFLAGS) -c main.c -o main.o | |
11 | ||
12 | clean: | |
13 | rm -f bhuna *.o *.so | |
14 | ||
15 | strip: bhuna | |
16 | strip bhuna | |
17 | ls -lah bhuna |
0 | #include <assert.h> | |
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | #include <unistd.h> | |
4 | ||
5 | #include "mem.h" | |
6 | #include "scan.h" | |
7 | #include "parse.h" | |
8 | #include "symbol.h" | |
9 | #include "ast.h" | |
10 | #include "builtin.h" | |
11 | #include "value.h" | |
12 | #include "activation.h" | |
13 | #include "vm.h" | |
14 | #include "type.h" | |
15 | #include "report.h" | |
16 | #include "gc.h" | |
17 | #include "trace.h" | |
18 | #include "process.h" | |
19 | ||
20 | #ifdef POOL_VALUES | |
21 | #include "pool.h" | |
22 | #endif | |
23 | ||
24 | #ifdef DEBUG | |
25 | #define OPTS "cdgG:lmnopsvy" | |
26 | #define RUN_PROGRAM run_program | |
27 | #else | |
28 | #define OPTS "G:" | |
29 | #define RUN_PROGRAM 1 | |
30 | #endif | |
31 | ||
32 | struct activation *global_ar; | |
33 | ||
34 | extern int gc_trigger; | |
35 | extern int gc_target; | |
36 | ||
37 | void | |
38 | usage(char **argv) | |
39 | { | |
40 | fprintf(stderr, "Usage: %s [-" OPTS "] source\n", | |
41 | argv[0]); | |
42 | #ifdef DEBUG | |
43 | fprintf(stderr, " -c: trace process context switching\n"); | |
44 | fprintf(stderr, " -d: trace pooling\n"); | |
45 | fprintf(stderr, " -g: trace garbage collection\n"); | |
46 | #endif | |
47 | fprintf(stderr, " -G int: set garbage collection threshold\n"); | |
48 | #ifdef DEBUG | |
49 | fprintf(stderr, " -l: trace bytecode generation (implies -x)\n"); | |
50 | fprintf(stderr, " -m: trace virtual machine\n"); | |
51 | fprintf(stderr, " -n: don't actually run program\n"); | |
52 | fprintf(stderr, " -o: trace allocations\n"); | |
53 | fprintf(stderr, " -p: dump program AST before run\n"); | |
54 | fprintf(stderr, " -s: dump symbol table before run\n"); | |
55 | fprintf(stderr, " -v: trace activation records\n"); | |
56 | fprintf(stderr, " -y: trace type inference\n"); | |
57 | #endif | |
58 | exit(1); | |
59 | } | |
60 | ||
61 | int | |
62 | main(int argc, char **argv) | |
63 | { | |
64 | char **real_argv = argv; | |
65 | struct scan_st *sc; | |
66 | struct symbol_table *stab; | |
67 | struct ast *a; | |
68 | char *source = NULL; | |
69 | int opt; | |
70 | int err_count = 0; | |
71 | #ifdef DEBUG | |
72 | int run_program = 1; | |
73 | int dump_symbols = 0; | |
74 | int dump_program = 0; | |
75 | #endif | |
76 | ||
77 | #ifdef DEBUG | |
78 | setvbuf(stdout, NULL, _IOLBF, 0); | |
79 | #endif | |
80 | ||
81 | /* | |
82 | * Get command-line arguments. | |
83 | */ | |
84 | while ((opt = getopt(argc, argv, OPTS)) != -1) { | |
85 | switch(opt) { | |
86 | #ifdef DEBUG | |
87 | case 'c': | |
88 | trace_scheduling++; | |
89 | break; | |
90 | #ifdef POOL_VALUES | |
91 | case 'd': | |
92 | trace_pool++; | |
93 | break; | |
94 | #endif | |
95 | case 'g': | |
96 | trace_gc++; | |
97 | break; | |
98 | #endif | |
99 | case 'G': | |
100 | gc_trigger = atoi(optarg); | |
101 | break; | |
102 | #ifdef DEBUG | |
103 | case 'l': | |
104 | trace_gen++; | |
105 | break; | |
106 | case 'm': | |
107 | trace_vm++; | |
108 | break; | |
109 | case 'n': | |
110 | run_program = 0; | |
111 | break; | |
112 | case 'o': | |
113 | trace_valloc++; | |
114 | break; | |
115 | case 'p': | |
116 | dump_program = 1; | |
117 | break; | |
118 | case 's': | |
119 | dump_symbols = 1; | |
120 | break; | |
121 | case 'v': | |
122 | trace_activations++; | |
123 | break; | |
124 | case 'y': | |
125 | trace_type_inference++; | |
126 | break; | |
127 | #endif | |
128 | case '?': | |
129 | default: | |
130 | usage(argv); | |
131 | } | |
132 | } | |
133 | argc -= optind; | |
134 | argv += optind; | |
135 | ||
136 | if (*argv != NULL) | |
137 | source = *argv; | |
138 | else | |
139 | usage(real_argv); | |
140 | ||
141 | #ifdef POOL_VALUES | |
142 | value_pool_new(); | |
143 | #endif | |
144 | ||
145 | gc_target = gc_trigger; | |
146 | if ((sc = scan_open(source)) != NULL) { | |
147 | stab = symbol_table_new(NULL, 0); | |
148 | global_ar = activation_new_on_heap(100, NULL, NULL); | |
149 | register_std_builtins(stab); | |
150 | report_start(); | |
151 | a = parse_program(sc, stab); | |
152 | scan_close(sc); | |
153 | #ifdef DEBUG | |
154 | if (dump_symbols) | |
155 | symbol_table_dump(stab, 1); | |
156 | if (dump_program) { | |
157 | ast_dump(a, 0); | |
158 | } | |
159 | #endif | |
160 | #ifndef DEBUG | |
161 | symbol_table_free(stab); | |
162 | types_free(); | |
163 | #endif | |
164 | err_count = report_finish(); | |
165 | if (err_count == 0) { | |
166 | struct vm *vm; | |
167 | struct process *p; | |
168 | unsigned char *program; | |
169 | ||
170 | program = bhuna_malloc(16384); | |
171 | ast_gen(&program, a); | |
172 | vm = vm_new(program, 16384); | |
173 | vm_set_pc(vm, program); | |
174 | vm->current_ar = global_ar; | |
175 | p = process_new(vm); | |
176 | /* ast_dump(a, 0); */ | |
177 | if (RUN_PROGRAM) { | |
178 | process_scheduler(); | |
179 | } | |
180 | vm_free(vm); | |
181 | bhuna_free(program); | |
182 | /*value_dump_global_table();*/ | |
183 | } | |
184 | ||
185 | ast_free(a); /* XXX move on up */ | |
186 | /* gc(); */ /* actually do a full blow out at the end */ | |
187 | /* activation_free_from_stack(global_ar); */ | |
188 | #ifdef DEBUG | |
189 | symbol_table_free(stab); | |
190 | types_free(); | |
191 | if (trace_valloc > 0) { | |
192 | value_dump_global_table(); | |
193 | printf("Created: %8d\n", num_vars_created); | |
194 | printf("Cached: %8d\n", num_vars_cached); | |
195 | printf("Freed: %8d\n", num_vars_freed); | |
196 | } | |
197 | if (trace_activations > 0) { | |
198 | printf("AR's alloc'ed: %8d\n", activations_allocated); | |
199 | printf("AR's freed: %8d\n", activations_freed); | |
200 | } | |
201 | #ifdef POOL_VALUES | |
202 | if (trace_pool > 0) { | |
203 | pool_report(); | |
204 | } | |
205 | #endif | |
206 | #endif | |
207 | return(0); | |
208 | } else { | |
209 | fprintf(stderr, "Can't open `%s'\n", source); | |
210 | return(1); | |
211 | } | |
212 | } |
0 | #ifdef RECURSIVE_AST_EVALUATOR | |
1 | ||
2 | #include <assert.h> | |
3 | #include <stdio.h> | |
4 | #include <stdlib.h> | |
5 | #include <string.h> | |
6 | ||
7 | #include "ast.h" | |
8 | #include "value.h" | |
9 | #include "list.h" | |
10 | #include "closure.h" | |
11 | #include "activation.h" | |
12 | #include "builtin.h" | |
13 | ||
14 | #ifdef DEBUG | |
15 | #include "symbol.h" | |
16 | ||
17 | extern int trace_assignments; | |
18 | extern int trace_calls; | |
19 | extern int trace_ast; | |
20 | extern int trace_closures; | |
21 | #endif | |
22 | ||
23 | extern struct activation *current_ar; | |
24 | ||
25 | static struct value *initializer; | |
26 | ||
27 | void | |
28 | ast_eval_init(void) | |
29 | { | |
30 | initializer = value_new_integer(76); | |
31 | } | |
32 | ||
33 | /*** OPERATIONS ***/ | |
34 | ||
35 | /* | |
36 | * Fill out an activation record with arguments. | |
37 | * Unlike ast_eval(), this is iterative. | |
38 | */ | |
39 | static void | |
40 | ast_fillout(struct ast *a, struct activation *ar) | |
41 | { | |
42 | struct value *v; | |
43 | int idxp; | |
44 | ||
45 | for (idxp = 0; a != NULL; a = a->u.arg.right) { | |
46 | assert(a->type == AST_ARG); | |
47 | v = NULL; | |
48 | ast_eval(a->u.arg.left, &v); | |
49 | activation_set_value(ar, idxp++, 0, v); | |
50 | value_release(v); | |
51 | } | |
52 | ||
53 | /* | |
54 | while (idxp < ar->size) { | |
55 | // printf("unfilled local or temporary @ %d\n", idxp); | |
56 | activation_set_value(ar, idxp++, 0, initializer); | |
57 | } | |
58 | */ | |
59 | } | |
60 | ||
61 | /*** EVALUATOR ***/ | |
62 | ||
63 | /* | |
64 | * a is roughly analogous to the program counter (PC.) | |
65 | * | |
66 | * v is roughly analogous to the accumulator (A) or top of stack (ToS). | |
67 | */ | |
68 | void | |
69 | ast_eval(struct ast *a, struct value **v) | |
70 | { | |
71 | struct value *l = NULL, *r = NULL, *lv = NULL; | |
72 | /* struct value **q = NULL; */ | |
73 | struct activation *new_ar = NULL; | |
74 | int i; | |
75 | ||
76 | if (a == NULL) | |
77 | return; | |
78 | ||
79 | #ifdef DEBUG | |
80 | if (trace_ast) { | |
81 | printf(">>> ENTERING %s[0x%08lx]\n", ast_name(a), (unsigned long)a); | |
82 | } | |
83 | #endif | |
84 | ||
85 | switch (a->type) { | |
86 | case AST_LOCAL: | |
87 | /* | |
88 | printf("index = %d, upcount = %d\n", | |
89 | a->u.local.index, a->u.local.upcount); | |
90 | activation_dump(current_ar, 0); | |
91 | printf("\n"); | |
92 | */ | |
93 | lv = activation_get_value(current_ar, | |
94 | a->u.local.index, a->u.local.upcount); | |
95 | assert(lv != NULL); | |
96 | value_set_from_value(v, lv); | |
97 | /*value_release(lv);*/ | |
98 | break; | |
99 | case AST_VALUE: | |
100 | value_set_from_value(v, a->u.value.value); | |
101 | if (*v != NULL && (*v)->type == VALUE_CLOSURE) { | |
102 | #ifdef DEBUG | |
103 | if (trace_closures) { | |
104 | printf("Freshening "); | |
105 | closure_dump((*v)->v.k); | |
106 | printf(" with "); | |
107 | activation_dump(current_ar, 1); | |
108 | printf("\n"); | |
109 | } | |
110 | #endif | |
111 | (*v)->v.k->ar = current_ar; | |
112 | } | |
113 | /*value_release(a->u.value.value);*/ | |
114 | break; | |
115 | case AST_BUILTIN: | |
116 | ast_eval(a->u.builtin.left, &l); | |
117 | ast_eval(a->u.builtin.right, &r); | |
118 | ||
119 | /* | |
120 | switch (a->u.builtin.bi->fn) { | |
121 | case builtin_not: | |
122 | case builtin_and: | |
123 | case builtin_or: | |
124 | ||
125 | case builtin_equ: | |
126 | case builtin_neq: | |
127 | case builtin_gt: | |
128 | case builtin_lt: | |
129 | case builtin_gte: | |
130 | case builtin_lte: | |
131 | ||
132 | case builtin_add: | |
133 | case builtin_mul: | |
134 | case builtin_sub: | |
135 | case builtin_div: | |
136 | case builtin_mod: | |
137 | default: | |
138 | break; | |
139 | } | |
140 | */ | |
141 | ||
142 | #ifdef INLINE_BUILTINS | |
143 | switch (a->u.builtin.bi->index) { | |
144 | case INDEX_BUILTIN_NOT: | |
145 | if (l->type == VALUE_BOOLEAN) { | |
146 | value_set_boolean(v, !l->v.b); | |
147 | } else { | |
148 | value_set_error(v, "type mismatch"); | |
149 | } | |
150 | break; | |
151 | case INDEX_BUILTIN_AND: | |
152 | if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) { | |
153 | value_set_boolean(v, l->v.b && r->v.b); | |
154 | } else { | |
155 | value_set_error(v, "type mismatch"); | |
156 | } | |
157 | break; | |
158 | case INDEX_BUILTIN_OR: | |
159 | if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) { | |
160 | value_set_boolean(v, l->v.b || r->v.b); | |
161 | } else { | |
162 | value_set_error(v, "type mismatch"); | |
163 | } | |
164 | break; | |
165 | ||
166 | case INDEX_BUILTIN_EQU: | |
167 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
168 | value_set_boolean(v, l->v.i == r->v.i); | |
169 | } else { | |
170 | value_set_error(v, "type mismatch"); | |
171 | } | |
172 | break; | |
173 | case INDEX_BUILTIN_NEQ: | |
174 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
175 | value_set_boolean(v, l->v.i != r->v.i); | |
176 | } else { | |
177 | value_set_error(v, "type mismatch"); | |
178 | } | |
179 | break; | |
180 | case INDEX_BUILTIN_GT: | |
181 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
182 | value_set_boolean(v, l->v.i > r->v.i); | |
183 | } else { | |
184 | value_set_error(v, "type mismatch"); | |
185 | } | |
186 | break; | |
187 | case INDEX_BUILTIN_LT: | |
188 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
189 | value_set_boolean(v, l->v.i < r->v.i); | |
190 | } else { | |
191 | value_set_error(v, "type mismatch"); | |
192 | } | |
193 | break; | |
194 | case INDEX_BUILTIN_GTE: | |
195 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
196 | value_set_boolean(v, l->v.i >= r->v.i); | |
197 | } else { | |
198 | value_set_error(v, "type mismatch"); | |
199 | } | |
200 | break; | |
201 | case INDEX_BUILTIN_LTE: | |
202 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
203 | value_set_boolean(v, l->v.i <= r->v.i); | |
204 | } else { | |
205 | value_set_error(v, "type mismatch"); | |
206 | } | |
207 | break; | |
208 | ||
209 | case INDEX_BUILTIN_ADD: | |
210 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
211 | value_set_integer(v, l->v.i + r->v.i); | |
212 | } else { | |
213 | value_set_error(v, "type mismatch"); | |
214 | } | |
215 | break; | |
216 | case INDEX_BUILTIN_MUL: | |
217 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
218 | value_set_integer(v, l->v.i * r->v.i); | |
219 | } else { | |
220 | value_set_error(v, "type mismatch"); | |
221 | } | |
222 | break; | |
223 | case INDEX_BUILTIN_SUB: | |
224 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
225 | value_set_integer(v, l->v.i - r->v.i); | |
226 | } else { | |
227 | value_set_error(v, "type mismatch"); | |
228 | } | |
229 | break; | |
230 | case INDEX_BUILTIN_DIV: | |
231 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
232 | if (r->v.i == 0) | |
233 | value_set_error(v, "division by zero"); | |
234 | else | |
235 | value_set_integer(v, l->v.i / r->v.i); | |
236 | } else { | |
237 | value_set_error(v, "type mismatch"); | |
238 | } | |
239 | break; | |
240 | case INDEX_BUILTIN_MOD: | |
241 | if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) { | |
242 | if (r->v.i == 0) | |
243 | value_set_error(v, "modulo by zero"); | |
244 | else | |
245 | value_set_integer(v, l->v.i % r->v.i); | |
246 | } else { | |
247 | value_set_error(v, "type mismatch"); } | |
248 | break; | |
249 | ||
250 | default: | |
251 | #endif | |
252 | /*printf("doing builtin %s\n", a->u.builtin.bi->name);*/ | |
253 | new_ar = activation_new(a->u.builtin.bi->arity, current_ar, NULL); | |
254 | if (a->u.builtin.bi->arity > 0) { | |
255 | activation_set_value(new_ar, 0, 0, l); | |
256 | if (a->u.builtin.bi->arity > 1) { | |
257 | activation_set_value(new_ar, 1, 0, r); | |
258 | } | |
259 | } | |
260 | a->u.builtin.bi->fn(new_ar, v); | |
261 | activation_free(new_ar); | |
262 | #ifdef INLINE_BUILTINS | |
263 | break; | |
264 | } | |
265 | #endif | |
266 | value_release(l); | |
267 | value_release(r); | |
268 | break; | |
269 | case AST_APPLY: | |
270 | /* | |
271 | * Get the function we're being asked to apply. | |
272 | */ | |
273 | ast_eval(a->u.apply.left, &l); | |
274 | assert(l->type == VALUE_CLOSURE); | |
275 | ||
276 | /* | |
277 | * Create a new activation record apropos to l. | |
278 | * Include the closure's environment as the | |
279 | * lexical link of the activation record. | |
280 | * | |
281 | * An optimization: if the closure we are executing here | |
282 | * contains no closures of its own, this activation record | |
283 | * will never be used by any other closure, so we don't | |
284 | * have to keep it on the heap nor garbage collect it. | |
285 | * We allocate it on the (C) stack instead. | |
286 | */ | |
287 | if (l->v.k->cc == 0) { | |
288 | /*printf("stack allocation!\n");*/ | |
289 | new_ar = alloca(sizeof(struct activation) + | |
290 | sizeof(struct value *) * l->v.k->arity); | |
291 | bzero(new_ar, sizeof(struct activation) + | |
292 | sizeof(struct value *) * l->v.k->arity); | |
293 | new_ar->size = l->v.k->arity; | |
294 | new_ar->caller = current_ar; | |
295 | new_ar->enclosing = l->v.k->ar; | |
296 | new_ar->marked = 0; | |
297 | } else { | |
298 | new_ar = activation_new(l->v.k->arity, | |
299 | current_ar, l->v.k->ar); | |
300 | } | |
301 | ||
302 | /* | |
303 | * Now, fill out that activation record with the | |
304 | * supplied arguments. | |
305 | * | |
306 | * Note that, because ast_fillout() is mutually recursive with | |
307 | * ast_eval(), and thus another AST_APPLY could be | |
308 | * encountered, which could cause a new activation record | |
309 | * to be created, which in turn could trigger the garbage | |
310 | * collector, we have deferred registering the new activation | |
311 | * record with the garbage collector until after this has | |
312 | * finished. | |
313 | */ | |
314 | ast_fillout(a->u.apply.right, new_ar); | |
315 | /* | |
316 | printf(":: filled out:\n"); | |
317 | activation_dump(new_ar, 1); | |
318 | printf("\n"); | |
319 | */ | |
320 | ||
321 | #ifdef DEBUG | |
322 | if (trace_calls) { | |
323 | printf("---> call:"); | |
324 | value_print(l); | |
325 | printf("("); | |
326 | activation_dump(current_ar, 1); | |
327 | printf(")\n"); | |
328 | } | |
329 | #endif | |
330 | /* | |
331 | * On the other hand, if the closure we are executing here | |
332 | * DOES contains closures of its own, we DO have to | |
333 | * register it with the garbage collector. | |
334 | */ | |
335 | if (l->v.k->cc > 0) | |
336 | activation_register(new_ar); | |
337 | ||
338 | /* | |
339 | * Evaluate it, under the new activation record. | |
340 | */ | |
341 | current_ar = new_ar; | |
342 | ast_eval(l->v.k->ast, v); | |
343 | assert(current_ar == new_ar); | |
344 | current_ar = current_ar->caller; | |
345 | ||
346 | if (l->v.k->cc == 0) { | |
347 | for (i = 0; i < l->v.k->arity; i++) { | |
348 | value_release( | |
349 | ((struct value **)((char *)new_ar + | |
350 | sizeof(struct activation)))[i] | |
351 | ); | |
352 | } | |
353 | } | |
354 | ||
355 | #ifdef DEBUG | |
356 | if (trace_calls) { | |
357 | printf("<--- call done, retval="); | |
358 | value_print(*v); | |
359 | printf("\n"); | |
360 | } | |
361 | #endif | |
362 | ||
363 | value_release(l); | |
364 | break; | |
365 | case AST_ARG: | |
366 | assert("this should never happen" == NULL); | |
367 | /*value_set_list(v); | |
368 | ast_flatten(a, v);*/ | |
369 | break; | |
370 | case AST_STATEMENT: | |
371 | ast_eval(a->u.statement.left, &l); | |
372 | value_release(l); | |
373 | ast_eval(a->u.statement.right, v); | |
374 | break; | |
375 | case AST_ASSIGNMENT: | |
376 | ast_eval(a->u.assignment.right, v); | |
377 | assert(a->u.assignment.left != NULL); | |
378 | assert(a->u.assignment.left->type == AST_LOCAL); | |
379 | ||
380 | activation_set_value(current_ar, | |
381 | a->u.assignment.left->u.local.index, | |
382 | a->u.assignment.left->u.local.upcount, | |
383 | *v); | |
384 | #ifdef DEBUG | |
385 | if (trace_assignments) { | |
386 | symbol_dump(a->u.assignment.left->u.local.sym, 1); | |
387 | printf(":="); | |
388 | value_print(*v); | |
389 | printf("\n"); | |
390 | } | |
391 | #endif | |
392 | break; | |
393 | case AST_CONDITIONAL: | |
394 | /* | |
395 | l = activation_get_value(current_ar, | |
396 | a->u.conditional.index, 0); | |
397 | */ | |
398 | ||
399 | /* | |
400 | q = &((struct value **)((char *)current_ar + | |
401 | sizeof(struct activation)))[a->u.conditional.index]; | |
402 | */ | |
403 | ast_eval(a->u.conditional.test, &l); | |
404 | ||
405 | if (l == NULL || l->type != VALUE_BOOLEAN) { | |
406 | value_set_error(v, "type mismatch"); | |
407 | } else { | |
408 | if (l->v.b) { | |
409 | ast_eval(a->u.conditional.yes, v); | |
410 | } else if (a->u.conditional.no != NULL) { | |
411 | ast_eval(a->u.conditional.no, v); | |
412 | } else { | |
413 | /* | |
414 | value_set_error(v, "missing else"); | |
415 | */ | |
416 | } | |
417 | } | |
418 | value_release(l); | |
419 | break; | |
420 | case AST_WHILE_LOOP: | |
421 | for (;;) { | |
422 | ast_eval(a->u.while_loop.test, &l); | |
423 | if (l == NULL || l->type != VALUE_BOOLEAN) { | |
424 | value_release(l); | |
425 | value_set_error(v, "type mismatch"); | |
426 | break; | |
427 | } else { | |
428 | /* | |
429 | printf("WHILE: test="); | |
430 | value_print(l); | |
431 | printf("\n"); | |
432 | */ | |
433 | if (!l->v.b) { | |
434 | /* | |
435 | * `while' condition evaluated to false. | |
436 | */ | |
437 | value_release(l); | |
438 | break; | |
439 | } | |
440 | ast_eval(a->u.while_loop.body, v); | |
441 | /* | |
442 | printf("WHILE: body="); | |
443 | value_print(*v); | |
444 | printf("\n"); | |
445 | */ | |
446 | } | |
447 | } | |
448 | break; | |
449 | } | |
450 | ||
451 | #ifdef DEBUG | |
452 | if (trace_ast) { | |
453 | printf("<<< LEAVING %s[0x%08lx] w/value=", ast_name(a), (unsigned long)a); | |
454 | value_print(*v); | |
455 | printf("\n"); | |
456 | } | |
457 | #endif | |
458 | } | |
459 | ||
460 | #endif /* RECURSIVE_AST_EVALUATOR */ |
0 | #include <assert.h> | |
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | ||
5 | #include "vm.h" | |
6 | #include "ast.h" | |
7 | #include "value.h" | |
8 | #include "list.h" | |
9 | #include "closure.h" | |
10 | #include "activation.h" | |
11 | #include "builtin.h" | |
12 | ||
13 | extern int trace_gen; | |
14 | ||
15 | static vm_label_t gptr; | |
16 | unsigned char program[65536]; | |
17 | ||
18 | vm_label_t patch_stack[4096]; | |
19 | int psp = 0; | |
20 | ||
21 | unsigned char *last_ins_at = NULL; | |
22 | unsigned char last_ins = 255; | |
23 | ||
24 | /*** backpatcher ***/ | |
25 | ||
26 | static int | |
27 | request_backpatch(vm_label_t *bp) | |
28 | { | |
29 | #ifdef DEBUG | |
30 | if (trace_gen) | |
31 | printf("[--> #%d]", *bp - program); | |
32 | #endif | |
33 | patch_stack[psp++] = *bp; | |
34 | *bp += sizeof(vm_label_t); | |
35 | return(psp - 1); | |
36 | } | |
37 | ||
38 | static void | |
39 | backpatch(int bpid) | |
40 | { | |
41 | vm_label_t bp; | |
42 | ||
43 | bp = patch_stack[bpid]; | |
44 | *(vm_label_t *)bp = gptr; | |
45 | #ifdef DEBUG | |
46 | if (trace_gen) | |
47 | printf("#%d: [<-- #%d] $%d:\n", gptr - program, bp - program, bpid); | |
48 | #endif | |
49 | } | |
50 | ||
51 | /*** generators ***/ | |
52 | ||
53 | static void | |
54 | gen(unsigned char ins) | |
55 | { | |
56 | last_ins_at = gptr; | |
57 | *gptr++ = last_ins = ins; | |
58 | } | |
59 | ||
60 | static void | |
61 | gen_push_value(struct value *v) | |
62 | { | |
63 | #ifdef DEBUG | |
64 | if (trace_gen) { | |
65 | printf("#%d: *PUSH_VALUE(", gptr - program); | |
66 | value_print(v); | |
67 | printf(")\n"); | |
68 | } | |
69 | #endif | |
70 | ||
71 | gen(INSTR_PUSH_VALUE); | |
72 | value_grab(v); | |
73 | *(((struct value **)gptr)++) = v; | |
74 | } | |
75 | ||
76 | static void | |
77 | gen_push_local(int index, int upcount) | |
78 | { | |
79 | #ifdef DEBUG | |
80 | if (trace_gen) | |
81 | printf("#%d: *PUSH_LOCAL(%d,%d)\n", gptr - program, index, upcount); | |
82 | #endif | |
83 | ||
84 | gen(INSTR_PUSH_LOCAL); | |
85 | *gptr++ = (unsigned char)index; | |
86 | *gptr++ = (unsigned char)upcount; | |
87 | } | |
88 | ||
89 | static void | |
90 | gen_pop_local(int index, int upcount) | |
91 | { | |
92 | #ifdef DEBUG | |
93 | if (trace_gen) | |
94 | printf("#%d: *POP_LOCAL(%d,%d)\n", gptr - program, index, upcount); | |
95 | #endif | |
96 | ||
97 | gen(INSTR_POP_LOCAL); | |
98 | *gptr++ = (unsigned char)index; | |
99 | *gptr++ = (unsigned char)upcount; | |
100 | } | |
101 | ||
102 | static void | |
103 | gen_builtin(struct builtin *bi) | |
104 | { | |
105 | #ifdef DEBUG | |
106 | if (trace_gen) | |
107 | printf("#%d: *BUILTIN(%s)\n", gptr - program, bi->name); | |
108 | #endif | |
109 | ||
110 | gen(bi->index); | |
111 | } | |
112 | ||
113 | static void | |
114 | gen_jz_bp(int *bpid) | |
115 | { | |
116 | #ifdef DEBUG | |
117 | if (trace_gen) | |
118 | printf("#%d: *JZ", gptr - program); | |
119 | #endif | |
120 | gen(INSTR_JZ); | |
121 | *bpid = request_backpatch(&gptr); | |
122 | #ifdef DEBUG | |
123 | if (trace_gen) | |
124 | printf("($%d)\n", *bpid); | |
125 | #endif | |
126 | } | |
127 | ||
128 | static void | |
129 | gen_jmp_bp(int *bpid) | |
130 | { | |
131 | #ifdef DEBUG | |
132 | if (trace_gen) | |
133 | printf("#%d: *JMP", gptr - program); | |
134 | #endif | |
135 | gen(INSTR_JMP); | |
136 | *bpid = request_backpatch(&gptr); | |
137 | #ifdef DEBUG | |
138 | if (trace_gen) | |
139 | printf("($%d)\n", *bpid); | |
140 | #endif | |
141 | } | |
142 | ||
143 | static void | |
144 | gen_jmp(vm_label_t label) | |
145 | { | |
146 | #ifdef DEBUG | |
147 | if (trace_gen) | |
148 | printf("#%d: *JMP", gptr - program); | |
149 | #endif | |
150 | gen(INSTR_JMP); | |
151 | *(vm_label_t *)gptr = label; | |
152 | gptr += sizeof(vm_label_t); | |
153 | #ifdef DEBUG | |
154 | if (trace_gen) | |
155 | printf("(#%d)\n", label - program); | |
156 | #endif | |
157 | } | |
158 | ||
159 | static void | |
160 | gen_apply(void) | |
161 | { | |
162 | #ifdef DEBUG | |
163 | if (trace_gen) | |
164 | printf("#%d: *CALL\n", gptr - program); | |
165 | #endif | |
166 | gen(INSTR_CALL); | |
167 | } | |
168 | ||
169 | static void | |
170 | gen_ret(void) | |
171 | { | |
172 | #ifdef DEBUG | |
173 | if (trace_gen) | |
174 | printf("#%d: *RET\n", gptr - program); | |
175 | #endif | |
176 | if (last_ins == INSTR_CALL) { | |
177 | #ifdef DEBUG | |
178 | if (trace_gen) | |
179 | printf("*** ELIMINATING TAIL CALL\n"); | |
180 | #endif | |