aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-09 19:00:17 +0200
committerBad Diode <bd@badd10de.dev>2021-10-09 19:00:17 +0200
commit859c33f37f0174a7b9d76cdcbe889ff12047c99c (patch)
tree418654fdc6594dfbfde1b092b7fa346958c8a746
parent376b83e6a44271599ed563e3510b2411beab5921 (diff)
downloadbdl-859c33f37f0174a7b9d76cdcbe889ff12047c99c.tar.gz
bdl-859c33f37f0174a7b9d76cdcbe889ff12047c99c.zip
Split main into separate files
-rw-r--r--src/bootstrap/environment.c23
-rw-r--r--src/bootstrap/lexer.c207
-rwxr-xr-xsrc/bootstrap/main.c674
-rw-r--r--src/bootstrap/objects.c156
-rw-r--r--src/bootstrap/parser.c78
-rw-r--r--src/bootstrap/primitives.c151
-rw-r--r--src/bootstrap/readline.c28
-rw-r--r--src/bootstrap/string_view.c25
8 files changed, 675 insertions, 667 deletions
diff --git a/src/bootstrap/environment.c b/src/bootstrap/environment.c
new file mode 100644
index 0000000..4eda2ad
--- /dev/null
+++ b/src/bootstrap/environment.c
@@ -0,0 +1,23 @@
1//
2// Environment.
3//
4
5typedef struct EnvSymbol {
6 Object *symbol;
7 Object *value;
8} EnvSymbol;
9
10#define ENV_SIZE 256
11static EnvSymbol environment[ENV_SIZE];
12static size_t env_n = 0;
13
14Object *
15find_environment_symbol(Object *symbol) {
16 for (size_t i = 0; i < env_n; i++) {
17 if (symbol_eq(environment[i].symbol, symbol)) {
18 return environment[i].value;
19 }
20 }
21 return NULL;
22}
23
diff --git a/src/bootstrap/lexer.c b/src/bootstrap/lexer.c
new file mode 100644
index 0000000..dd5c0f2
--- /dev/null
+++ b/src/bootstrap/lexer.c
@@ -0,0 +1,207 @@
1typedef enum TokenType {
2 TOKEN_UNKNOWN = 0,
3 TOKEN_LPAREN,
4 TOKEN_RPAREN,
5 TOKEN_FIXNUM,
6 TOKEN_SYMBOL,
7 TOKEN_BOOL,
8 TOKEN_STRING,
9} TokenType;
10
11typedef struct Token {
12 TokenType type;
13 StringView value;
14} Token;
15
16typedef struct Tokens {
17 Token *start;
18 size_t n;
19} Tokens;
20
21#define TRUE_TOKEN (StringView){"true", 4}
22#define FALSE_TOKEN (StringView){"false", 5}
23#define LPAREN_TOKEN (StringView){"(", 1}
24#define RPAREN_TOKEN (StringView){")", 1}
25
26TokenType
27find_token_type(StringView value) {
28 bool is_fixnum = true;
29 for (size_t i = 0; i < value.n; i++) {
30 char c = value.start[i];
31 if (i == 0 && c == '-' && value.n > 1) {
32 continue;
33 }
34 if (!isdigit(c)) {
35 is_fixnum = false;
36 break;
37 }
38 }
39 if (is_fixnum) {
40 return TOKEN_FIXNUM;
41 }
42
43 if (sv_equal(value, TRUE_TOKEN) || sv_equal(value, FALSE_TOKEN)) {
44 return TOKEN_BOOL;
45 }
46
47 return TOKEN_SYMBOL;
48}
49
50Tokens
51tokenize(StringView sv) {
52 // NOTE: Not allocating any memory for now, but we are limited by a maximum
53 // number of tokens we can process.
54 #define TOKENS_BUF_SIZE 1024
55 static Token tokens_buf[TOKENS_BUF_SIZE];
56
57 // Clear buffer.
58 for (size_t i = 0; i < TOKENS_BUF_SIZE; i++) {
59 tokens_buf[i] = (Token){0};
60 }
61
62 size_t n = 0;
63 size_t token_n = 0;
64 for (size_t i = 0; i < sv.n; i++) {
65 switch (sv.start[i]) {
66 case ' ':
67 case '\f':
68 case '\n':
69 case '\r':
70 case '\t':
71 case '\v': {
72 if (token_n != 0) {
73 Token token = (Token){
74 .type = TOKEN_UNKNOWN,
75 .value = (StringView){
76 .start = &sv.start[i - token_n],
77 .n = token_n,
78 }
79 };
80 token.type = find_token_type(token.value);
81 tokens_buf[n++] = token;
82 token_n = 0;
83 }
84 } break;
85 case ';': {
86 if (token_n != 0) {
87 Token token = (Token){
88 .type = TOKEN_UNKNOWN,
89 .value = (StringView){
90 .start = &sv.start[i - token_n],
91 .n = token_n,
92 }
93 };
94 token.type = find_token_type(token.value);
95 tokens_buf[n++] = token;
96 token_n = 0;
97 }
98
99 // Advance until the next newline.
100 do {
101 i++;
102 } while (i < sv.n && sv.start[(i + 1)] != '\n');
103 } break;
104 case '"': {
105 if (token_n != 0) {
106 fprintf(stderr, "error: string started inside symbol\n");
107 return (Tokens){0};
108 }
109
110 // Find end delimiter.
111 size_t string_start = i + 1;
112 size_t string_end = i + 1;
113 while (true) {
114 if (sv.start[string_end] == '"' && sv.start[string_end - 1] != '\\') {
115 break;
116 }
117 if (string_end >= sv.n) {
118 fprintf(stderr, "error: string delimiter not found\n");
119 return (Tokens){0};
120 }
121 string_end++;
122 }
123
124 Token token = (Token){
125 .type = TOKEN_STRING,
126 .value = (StringView){
127 .start = &sv.start[string_start],
128 .n = string_end - string_start,
129 }
130 };
131 tokens_buf[n++] = token;
132 token_n = 0;
133 i += string_end - string_start + 1;
134 } break;
135 case '(': {
136 if ((i + 1) < sv.n) {
137 char next_c = sv.start[i + 1];
138 if (isspace(next_c)) {
139 fprintf(stderr, "error: lparen delimiter followed by space\n");
140 return (Tokens){0};
141 }
142 }
143
144 if (token_n != 0) {
145 fprintf(stderr, "error: lparen delimiter within symbol name\n");
146 return (Tokens){0};
147 }
148
149 Token token = (Token){
150 .type = TOKEN_LPAREN,
151 .value = LPAREN_TOKEN,
152 };
153 tokens_buf[n++] = token;
154 } break;
155 case ')': {
156 if ((i + 1) < sv.n) {
157 char next_c = sv.start[i + 1];
158 if ((next_c != ')' && !isspace(next_c))) {
159 fprintf(stderr, "error: rparen delimiter within symbol name\n");
160 return (Tokens){0};
161 }
162 }
163
164 if (token_n != 0) {
165 // Push previous token.
166 Token token = (Token){
167 .type = TOKEN_UNKNOWN,
168 .value = (StringView){
169 .start = &sv.start[i - token_n],
170 .n = token_n,
171 }
172 };
173 token.type = find_token_type(token.value);
174 tokens_buf[n++] = token;
175 token_n = 0;
176 }
177
178 Token token = (Token){
179 .type = TOKEN_RPAREN,
180 .value = RPAREN_TOKEN,
181 };
182 tokens_buf[n++] = token;
183 } break;
184 case EOF: {
185 break;
186 } break;
187 default: {
188 token_n++;
189 } break;
190 }
191 }
192 if (token_n != 0) {
193 // End of line encountered.
194 Token token = (Token){
195 .type = TOKEN_UNKNOWN,
196 .value = (StringView){
197 .start = &sv.start[sv.n - token_n],
198 .n = token_n,
199 }
200 };
201 token.type = find_token_type(token.value);
202 tokens_buf[n++] = token;
203 }
204
205 return (Tokens){.start = (Token *)&tokens_buf, .n = n};
206}
207
diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c
index f5653d6..419ce91 100755
--- a/src/bootstrap/main.c
+++ b/src/bootstrap/main.c
@@ -5,644 +5,20 @@
5#include <string.h> 5#include <string.h>
6 6
7#include "shorthand.h" 7#include "shorthand.h"
8 8#include "string_view.c"
9#include "readline.c"
10#include "lexer.c"
11#include "objects.c"
12#include "parser.c"
13#include "environment.c"
14#include "primitives.c"
9 15
10// FIXME: We are not worried right now about freeing memory, but we should in 16// FIXME: We are not worried right now about freeing memory, but we should in
11// the future. 17// the future.
12// TODO: Better error messages. 18// TODO: Better error messages.
13 19
14typedef struct StringView {
15 char *start;
16 size_t n;
17} StringView;
18
19void
20sv_write(StringView sv) {
21 for (size_t i = 0; i < sv.n; i++) {
22 putchar(sv.start[i]);
23 }
24}
25
26bool
27sv_equal(StringView a, StringView b) {
28 if (a.n == b.n) {
29 for (size_t i = 0; i < a.n; i++) {
30 if (a.start[i] != b.start[i]) {
31 return false;
32 }
33 }
34 return true;
35 }
36 return false;
37}
38
39#define READLINE_VALID_CHAR(C) (((u8)(C) >= 0x20 && (u8)(C) < 0x7F) || (C) == '\n')
40
41StringView
42read_line(FILE *fd, char delimiter) {
43 #define RL_BUF_SIZE 1024
44 static char readline_buf[RL_BUF_SIZE];
45
46 // Clear buffer.
47 for (size_t i = 0; i < RL_BUF_SIZE; i++) {
48 readline_buf[i] = 0;
49 }
50
51 // Barebones readline implementation.
52 size_t n = 0;
53 char c;
54 while ((c = getc(fd)) != delimiter) {
55 if (c == '\b') {
56 readline_buf[n] = '\0';
57 n--;
58 } else if (READLINE_VALID_CHAR(c) && n < RL_BUF_SIZE) {
59 readline_buf[n] = c;
60 n++;
61 }
62 }
63
64 return (StringView){.start = (char *)&readline_buf, .n = n};
65}
66
67typedef enum TokenType {
68 TOKEN_UNKNOWN = 0,
69 TOKEN_LPAREN,
70 TOKEN_RPAREN,
71 TOKEN_FIXNUM,
72 TOKEN_SYMBOL,
73 TOKEN_BOOL,
74 TOKEN_STRING,
75} TokenType;
76
77typedef struct Token {
78 TokenType type;
79 StringView value;
80} Token;
81
82typedef struct Tokens {
83 Token *start;
84 size_t n;
85} Tokens;
86
87#define TRUE_TOKEN (StringView){"true", 4}
88#define FALSE_TOKEN (StringView){"false", 5}
89#define LPAREN_TOKEN (StringView){"(", 1}
90#define RPAREN_TOKEN (StringView){")", 1}
91
92TokenType
93find_token_type(StringView value) {
94 bool is_fixnum = true;
95 for (size_t i = 0; i < value.n; i++) {
96 char c = value.start[i];
97 if (i == 0 && c == '-' && value.n > 1) {
98 continue;
99 }
100 if (!isdigit(c)) {
101 is_fixnum = false;
102 break;
103 }
104 }
105 if (is_fixnum) {
106 return TOKEN_FIXNUM;
107 }
108
109 if (sv_equal(value, TRUE_TOKEN) || sv_equal(value, FALSE_TOKEN)) {
110 return TOKEN_BOOL;
111 }
112
113 return TOKEN_SYMBOL;
114}
115
116Tokens
117tokenize(StringView sv) {
118 // NOTE: Not allocating any memory for now, but we are limited by a maximum
119 // number of tokens we can process.
120 #define TOKENS_BUF_SIZE 1024
121 static Token tokens_buf[TOKENS_BUF_SIZE];
122
123 // Clear buffer.
124 for (size_t i = 0; i < TOKENS_BUF_SIZE; i++) {
125 tokens_buf[i] = (Token){0};
126 }
127
128 size_t n = 0;
129 size_t token_n = 0;
130 for (size_t i = 0; i < sv.n; i++) {
131 switch (sv.start[i]) {
132 case ' ':
133 case '\f':
134 case '\n':
135 case '\r':
136 case '\t':
137 case '\v': {
138 if (token_n != 0) {
139 Token token = (Token){
140 .type = TOKEN_UNKNOWN,
141 .value = (StringView){
142 .start = &sv.start[i - token_n],
143 .n = token_n,
144 }
145 };
146 token.type = find_token_type(token.value);
147 tokens_buf[n++] = token;
148 token_n = 0;
149 }
150 } break;
151 case ';': {
152 if (token_n != 0) {
153 Token token = (Token){
154 .type = TOKEN_UNKNOWN,
155 .value = (StringView){
156 .start = &sv.start[i - token_n],
157 .n = token_n,
158 }
159 };
160 token.type = find_token_type(token.value);
161 tokens_buf[n++] = token;
162 token_n = 0;
163 }
164
165 // Advance until the next newline.
166 do {
167 i++;
168 } while (i < sv.n && sv.start[(i + 1)] != '\n');
169 } break;
170 case '"': {
171 if (token_n != 0) {
172 fprintf(stderr, "error: string started inside symbol\n");
173 return (Tokens){0};
174 }
175
176 // Find end delimiter.
177 size_t string_start = i + 1;
178 size_t string_end = i + 1;
179 while (true) {
180 if (sv.start[string_end] == '"' && sv.start[string_end - 1] != '\\') {
181 break;
182 }
183 if (string_end >= sv.n) {
184 fprintf(stderr, "error: string delimiter not found\n");
185 return (Tokens){0};
186 }
187 string_end++;
188 }
189
190 Token token = (Token){
191 .type = TOKEN_STRING,
192 .value = (StringView){
193 .start = &sv.start[string_start],
194 .n = string_end - string_start,
195 }
196 };
197 tokens_buf[n++] = token;
198 token_n = 0;
199 i += string_end - string_start + 1;
200 } break;
201 case '(': {
202 if ((i + 1) < sv.n) {
203 char next_c = sv.start[i + 1];
204 if (isspace(next_c)) {
205 fprintf(stderr, "error: lparen delimiter followed by space\n");
206 return (Tokens){0};
207 }
208 }
209
210 if (token_n != 0) {
211 fprintf(stderr, "error: lparen delimiter within symbol name\n");
212 return (Tokens){0};
213 }
214
215 Token token = (Token){
216 .type = TOKEN_LPAREN,
217 .value = LPAREN_TOKEN,
218 };
219 tokens_buf[n++] = token;
220 } break;
221 case ')': {
222 if ((i + 1) < sv.n) {
223 char next_c = sv.start[i + 1];
224 if ((next_c != ')' && !isspace(next_c))) {
225 fprintf(stderr, "error: rparen delimiter within symbol name\n");
226 return (Tokens){0};
227 }
228 }
229
230 if (token_n != 0) {
231 // Push previous token.
232 Token token = (Token){
233 .type = TOKEN_UNKNOWN,
234 .value = (StringView){
235 .start = &sv.start[i - token_n],
236 .n = token_n,
237 }
238 };
239 token.type = find_token_type(token.value);
240 tokens_buf[n++] = token;
241 token_n = 0;
242 }
243
244 Token token = (Token){
245 .type = TOKEN_RPAREN,
246 .value = RPAREN_TOKEN,
247 };
248 tokens_buf[n++] = token;
249 } break;
250 case EOF: {
251 break;
252 } break;
253 default: {
254 token_n++;
255 } break;
256 }
257 }
258 if (token_n != 0) {
259 // End of line encountered.
260 Token token = (Token){
261 .type = TOKEN_UNKNOWN,
262 .value = (StringView){
263 .start = &sv.start[sv.n - token_n],
264 .n = token_n,
265 }
266 };
267 token.type = find_token_type(token.value);
268 tokens_buf[n++] = token;
269 }
270
271 return (Tokens){.start = (Token *)&tokens_buf, .n = n};
272}
273
274Token *
275consume_token(Tokens *tokens) {
276 if (tokens->n == 0) {
277 return NULL;
278 }
279 Token *ret = tokens->start;
280 tokens->start = &tokens->start[1];
281 tokens->n--;
282 return ret;
283}
284
285typedef enum ObjectType {
286 OBJ_TYPE_FIXNUM,
287 OBJ_TYPE_BOOL,
288 OBJ_TYPE_NIL,
289 OBJ_TYPE_SYMBOL,
290 OBJ_TYPE_STRING,
291 OBJ_TYPE_PAIR,
292 OBJ_TYPE_PROCEDURE,
293} ObjectType;
294
295typedef struct Object {
296 ObjectType type;
297 union {
298 // OBJ_TYPE_FIXNUM
299 ssize_t fixnum;
300
301 // OBJ_TYPE_BOOL
302 bool boolean;
303
304 // OBJ_TYPE_STRING
305 struct {
306 char *string;
307 size_t string_n;
308 };
309
310 // OBJ_TYPE_PAIR
311 struct {
312 struct Object *car;
313 struct Object *cdr;
314 };
315
316 // OBJ_TYPE_SYMBOL
317 struct {
318 char *symbol;
319 size_t symbol_n;
320 };
321
322 // OBJ_TYPE_PROCEDURE
323 struct Object *(*proc)(struct Object *args);
324 };
325} Object;
326
327//
328// Singletons.
329//
330
331Object *obj_nil;
332Object *obj_true;
333Object *obj_false;
334
335//
336// Environment.
337//
338
339typedef struct EnvSymbol {
340 Object *symbol;
341 Object *value;
342} EnvSymbol;
343
344#define ENV_SIZE 256
345static EnvSymbol environment[ENV_SIZE];
346static size_t env_n = 0;
347
348Object *
349make_fixnum(ssize_t num) {
350 Object *obj = malloc(sizeof(Object));
351 obj->type = OBJ_TYPE_FIXNUM;
352 obj->fixnum = num;
353 return obj;
354}
355
356Object *
357make_boolean(bool b) {
358 Object *obj = malloc(sizeof(Object));
359 obj->type = OBJ_TYPE_BOOL;
360 obj->boolean = b;
361 return obj;
362}
363
364Object *
365make_empty_string(void) {
366 Object *obj = malloc(sizeof(Object));
367 obj->type = OBJ_TYPE_STRING;
368 obj->string = NULL;
369 obj->string_n = 0;
370 return obj;
371}
372
373void
374append_string(Object *string, StringView sv) {
375 assert(string != NULL);
376 assert(string->type == OBJ_TYPE_STRING);
377
378 if (sv.n == 0) {
379 return;
380 }
381
382 string->string = realloc(string->string, (string->string_n + sv.n) * sizeof(char));
383 memcpy(string->string + string->string_n, sv.start, sv.n);
384 string->string_n += sv.n;
385}
386
387Object *
388make_symbol(const char *str, size_t n) {
389 Object *obj = malloc(sizeof(Object));
390 obj->type = OBJ_TYPE_SYMBOL;
391 obj->string = malloc(sizeof(char) * n);
392 memcpy(obj->string, str, n);
393 obj->string_n = n;
394 return obj;
395}
396
397Object *
398make_empty_list(void) {
399 Object *obj = malloc(sizeof(Object));
400 obj->type = OBJ_TYPE_NIL;
401 return obj;
402}
403
404Object *
405make_procedure(Object *(*proc)(struct Object *args)) {
406 Object *obj = malloc(sizeof(Object));
407 obj->type = OBJ_TYPE_PROCEDURE;
408 obj->proc = proc;
409 return obj;
410}
411
412Object *
413make_pair(Object *car, Object *cdr) {
414 Object *obj = malloc(sizeof(Object));
415 obj->type = OBJ_TYPE_PAIR;
416 obj->car = car;
417 obj->cdr = cdr;
418 return obj;
419}
420
421Object *
422parse(Tokens *tokens) {
423 while (tokens->n > 0) {
424 Token *token = consume_token(tokens);
425 if (token == NULL) {
426 return NULL;
427 }
428
429 switch (token->type) {
430 case TOKEN_FIXNUM: {
431 ssize_t num = 0;
432 int sign = 1;
433 for (size_t i = 0; i < token->value.n; i++) {
434 char c = token->value.start[i];
435 if (c == '-') {
436 sign = -1;
437 continue;
438 }
439 num = num * 10 + (c - '0');
440 }
441 return make_fixnum(num * sign);
442 } break;
443 case TOKEN_BOOL: {
444 if (sv_equal(token->value, TRUE_TOKEN)) {
445 return obj_true;
446 }
447 if (sv_equal(token->value, FALSE_TOKEN)) {
448 return obj_false;
449 }
450 } break;
451 case TOKEN_RPAREN: {
452 return NULL;
453 } break;
454 case TOKEN_LPAREN: {
455 if (tokens->n > 0 && tokens->start[0].type == TOKEN_RPAREN) {
456 return obj_nil;
457 }
458
459 Object *next_obj = parse(tokens);
460 if (next_obj == NULL) {
461 return NULL;
462 }
463 Object *root = make_pair(next_obj, obj_nil);
464 Object *list = root;
465 while (tokens->n > 0 && (next_obj = parse(tokens)) != NULL) {
466 list->cdr = make_pair(next_obj, obj_nil);
467 list = list->cdr;
468 }
469 return root;
470 } break;
471 case TOKEN_STRING: {
472 Object *obj = make_empty_string();
473 append_string(obj, token->value);
474 return obj;
475 } break;
476 case TOKEN_SYMBOL: {
477 return make_symbol(token->value.start, token->value.n);
478 } break;
479 default: {
480 fprintf(stderr, "error: unknown token\n");
481 } break;
482 }
483 }
484
485 return NULL;
486}
487
488void display(Object *root);
489
490void
491display_pair(Object *root) {
492 display(root->car);
493 if (root->cdr->type == OBJ_TYPE_PAIR) {
494 printf(" ");
495 display_pair(root->cdr);
496 } else if (root->cdr->type == OBJ_TYPE_NIL) {
497 return;
498 } else {
499 printf(" . ");
500 display(root->cdr);
501 }
502}
503
504void
505display(Object *root) {
506 if (root == NULL) {
507 return;
508 }
509
510 switch (root->type) {
511 case OBJ_TYPE_FIXNUM: {
512 printf("%zd", root->fixnum);
513 } break;
514 case OBJ_TYPE_BOOL: {
515 if (root->boolean) {
516 printf("true");
517 } else {
518 printf("false");
519 }
520 } break;
521 case OBJ_TYPE_NIL: {
522 printf("()");
523 } break;
524 case OBJ_TYPE_STRING: {
525 printf("\"%.*s\"", (int)root->string_n, root->string);
526 } break;
527 case OBJ_TYPE_SYMBOL: {
528 printf(":%.*s", (int)root->symbol_n, root->symbol);
529 } break;
530 case OBJ_TYPE_PAIR: {
531 printf("(");
532 display_pair(root);
533 printf(")");
534 } break;
535 default: {
536 printf("TYPE NOT IMPLEMENTED FOR DISPLAY.");
537 } break;
538 }
539}
540
541#define REPL_PROMPT "bdl> " 20#define REPL_PROMPT "bdl> "
542 21
543Object * eval(Object *root);
544
545Object *
546proc_add(Object *args) {
547 ssize_t tot = 0;
548 while (args->type == OBJ_TYPE_PAIR) {
549 Object *car = eval(args->car);
550 if (car->type != OBJ_TYPE_FIXNUM) {
551 fprintf(stderr, "addition not supported for type %d\n", car->type);
552 return NULL;
553 }
554 tot += car->fixnum;
555 args = args->cdr;
556 }
557 return make_fixnum(tot);
558}
559
560Object *
561proc_sub(Object *args) {
562 if (args->type != OBJ_TYPE_PAIR) {
563 fprintf(stderr, "substraction not supported for type %d\n", args->type);
564 return NULL;
565 }
566
567 // Extract first parameter.
568 Object *car = eval(args->car);
569 args = args->cdr;
570 ssize_t tot = car->fixnum;
571
572 while (args->type == OBJ_TYPE_PAIR) {
573 Object *car = eval(args->car);
574 if (car->type != OBJ_TYPE_FIXNUM) {
575 fprintf(stderr, "substraction not supported for type %d\n", car->type);
576 return NULL;
577 }
578 tot -= car->fixnum;
579 args = args->cdr;
580 }
581 return make_fixnum(tot);
582}
583
584Object *
585proc_mul(Object *args) {
586 ssize_t tot = 1;
587 while (args->type == OBJ_TYPE_PAIR) {
588 Object *car = eval(args->car);
589 if (car->type != OBJ_TYPE_FIXNUM) {
590 fprintf(stderr, "multiply not supported for type %d\n", car->type);
591 return NULL;
592 }
593 tot *= car->fixnum;
594 args = args->cdr;
595 }
596 return make_fixnum(tot);
597}
598
599Object *
600proc_div(Object *args) {
601 if (args->type != OBJ_TYPE_PAIR) {
602 fprintf(stderr, "substraction not supported for type %d\n", args->type);
603 return NULL;
604 }
605
606 // Extract first parameter.
607 Object *car = eval(args->car);
608 args = args->cdr;
609 ssize_t tot = car->fixnum;
610
611 while (args->type == OBJ_TYPE_PAIR) {
612 Object *car = eval(args->car);
613 if (car->type != OBJ_TYPE_FIXNUM) {
614 fprintf(stderr, "div not supported for type %d\n", car->type);
615 return NULL;
616 }
617 tot /= car->fixnum;
618 args = args->cdr;
619 }
620 return make_fixnum(tot);
621}
622
623bool
624symbol_eq(Object *a, Object *b) {
625 if (a->type != b->type || a->type != OBJ_TYPE_SYMBOL || a->symbol_n != b->symbol_n) {
626 return false;
627 }
628 for (size_t i = 0; i < a->symbol_n; i++) {
629 if (a->symbol[i] != b->symbol[i]) {
630 return false;
631 }
632 }
633 return true;
634}
635
636Object *
637find_environment_symbol(Object *symbol) {
638 for (size_t i = 0; i < env_n; i++) {
639 if (symbol_eq(environment[i].symbol, symbol)) {
640 return environment[i].value;
641 }
642 }
643 return NULL;
644}
645
646void 22void
647init(void) { 23init(void) {
648 // Clear env. 24 // Clear env.
@@ -662,42 +38,6 @@ init(void) {
662 environment[env_n++] = (EnvSymbol){make_symbol("/", 1), make_procedure(proc_div)}; 38 environment[env_n++] = (EnvSymbol){make_symbol("/", 1), make_procedure(proc_div)};
663} 39}
664 40
665Object *
666eval(Object *root) {
667 if (root == NULL) {
668 return NULL;
669 }
670
671 switch (root->type) {
672 case OBJ_TYPE_FIXNUM:
673 case OBJ_TYPE_BOOL:
674 case OBJ_TYPE_NIL:
675 case OBJ_TYPE_STRING:
676 case OBJ_TYPE_SYMBOL: {
677 return root;
678 } break;
679 case OBJ_TYPE_PAIR: {
680 if (root->car->type == OBJ_TYPE_SYMBOL) {
681 Object *value = find_environment_symbol(root->car);
682 if (value == NULL) {
683 printf("error: symbol not found: `");
684 display(root->car);
685 printf("`\n");
686 return NULL;
687 }
688 if (value->type == OBJ_TYPE_PROCEDURE) {
689 return value->proc(root->cdr);
690 }
691 }
692 } break;
693 default: {
694 printf("error: can't eval type %d.\n", root->type);
695 } break;
696 }
697
698 return NULL;
699}
700
701void 41void
702eval_line(FILE *fd, char delimiter) { 42eval_line(FILE *fd, char delimiter) {
703 StringView line = read_line(fd, delimiter); 43 StringView line = read_line(fd, delimiter);
diff --git a/src/bootstrap/objects.c b/src/bootstrap/objects.c
new file mode 100644
index 0000000..985709a
--- /dev/null
+++ b/src/bootstrap/objects.c
@@ -0,0 +1,156 @@
1typedef enum ObjectType {
2 OBJ_TYPE_FIXNUM,
3 OBJ_TYPE_BOOL,
4 OBJ_TYPE_NIL,
5 OBJ_TYPE_SYMBOL,
6 OBJ_TYPE_STRING,
7 OBJ_TYPE_PAIR,
8 OBJ_TYPE_PROCEDURE,
9} ObjectType;
10
11typedef struct Object {
12 ObjectType type;
13 union {
14 // OBJ_TYPE_FIXNUM
15 ssize_t fixnum;
16
17 // OBJ_TYPE_BOOL
18 bool boolean;
19
20 // OBJ_TYPE_STRING
21 struct {
22 char *string;
23 size_t string_n;
24 };
25
26 // OBJ_TYPE_PAIR
27 struct {
28 struct Object *car;
29 struct Object *cdr;
30 };
31
32 // OBJ_TYPE_SYMBOL
33 struct {
34 char *symbol;
35 size_t symbol_n;
36 };
37
38 // OBJ_TYPE_PROCEDURE
39 struct Object *(*proc)(struct Object *args);
40 };
41} Object;
42
43//
44// Singletons.
45//
46
47Object *obj_nil;
48Object *obj_true;
49Object *obj_false;
50
51//
52// Constructors.
53//
54
55Object *
56make_fixnum(ssize_t num) {
57 Object *obj = malloc(sizeof(Object));
58 obj->type = OBJ_TYPE_FIXNUM;
59 obj->fixnum = num;
60 return obj;
61}
62
63Object *
64make_boolean(bool b) {
65 Object *obj = malloc(sizeof(Object));
66 obj->type = OBJ_TYPE_BOOL;
67 obj->boolean = b;
68 return obj;
69}
70
71Object *
72make_empty_string(void) {
73 Object *obj = malloc(sizeof(Object));
74 obj->type = OBJ_TYPE_STRING;
75 obj->string = NULL;
76 obj->string_n = 0;
77 return obj;
78}
79
80void
81append_string(Object *string, StringView sv) {
82 assert(string != NULL);
83 assert(string->type == OBJ_TYPE_STRING);
84
85 if (sv.n == 0) {
86 return;
87 }
88
89 string->string = realloc(string->string, (string->string_n + sv.n) * sizeof(char));
90 memcpy(string->string + string->string_n, sv.start, sv.n);
91 string->string_n += sv.n;
92}
93
94Object *
95make_symbol(const char *str, size_t n) {
96 Object *obj = malloc(sizeof(Object));
97 obj->type = OBJ_TYPE_SYMBOL;
98 obj->string = malloc(sizeof(char) * n);
99 memcpy(obj->string, str, n);
100 obj->string_n = n;
101 return obj;
102}
103
104Object *
105make_empty_list(void) {
106 Object *obj = malloc(sizeof(Object));
107 obj->type = OBJ_TYPE_NIL;
108 return obj;
109}
110
111Object *
112make_procedure(Object *(*proc)(struct Object *args)) {
113 Object *obj = malloc(sizeof(Object));
114 obj->type = OBJ_TYPE_PROCEDURE;
115 obj->proc = proc;
116 return obj;
117}
118
119Object *
120make_pair(Object *car, Object *cdr) {
121 Object *obj = malloc(sizeof(Object));
122 obj->type = OBJ_TYPE_PAIR;
123 obj->car = car;
124 obj->cdr = cdr;
125 return obj;
126}
127
128bool
129symbol_eq(Object *a, Object *b) {
130 if (a->type != b->type || a->type != OBJ_TYPE_SYMBOL || a->symbol_n != b->symbol_n) {
131 return false;
132 }
133 for (size_t i = 0; i < a->symbol_n; i++) {
134 if (a->symbol[i] != b->symbol[i]) {
135 return false;
136 }
137 }
138 return true;
139}
140
141void display(Object *root);
142
143void
144display_pair(Object *root) {
145 display(root->car);
146 if (root->cdr->type == OBJ_TYPE_PAIR) {
147 printf(" ");
148 display_pair(root->cdr);
149 } else if (root->cdr->type == OBJ_TYPE_NIL) {
150 return;
151 } else {
152 printf(" . ");
153 display(root->cdr);
154 }
155}
156
diff --git a/src/bootstrap/parser.c b/src/bootstrap/parser.c
new file mode 100644
index 0000000..7a5b516
--- /dev/null
+++ b/src/bootstrap/parser.c
@@ -0,0 +1,78 @@
1Token *
2consume_token(Tokens *tokens) {
3 if (tokens->n == 0) {
4 return NULL;
5 }
6 Token *ret = tokens->start;
7 tokens->start = &tokens->start[1];
8 tokens->n--;
9 return ret;
10}
11
12Object *
13parse(Tokens *tokens) {
14 while (tokens->n > 0) {
15 Token *token = consume_token(tokens);
16 if (token == NULL) {
17 return NULL;
18 }
19
20 switch (token->type) {
21 case TOKEN_FIXNUM: {
22 ssize_t num = 0;
23 int sign = 1;
24 for (size_t i = 0; i < token->value.n; i++) {
25 char c = token->value.start[i];
26 if (c == '-') {
27 sign = -1;
28 continue;
29 }
30 num = num * 10 + (c - '0');
31 }
32 return make_fixnum(num * sign);
33 } break;
34 case TOKEN_BOOL: {
35 if (sv_equal(token->value, TRUE_TOKEN)) {
36 return obj_true;
37 }
38 if (sv_equal(token->value, FALSE_TOKEN)) {
39 return obj_false;
40 }
41 } break;
42 case TOKEN_RPAREN: {
43 return NULL;
44 } break;
45 case TOKEN_LPAREN: {
46 if (tokens->n > 0 && tokens->start[0].type == TOKEN_RPAREN) {
47 return obj_nil;
48 }
49
50 Object *next_obj = parse(tokens);
51 if (next_obj == NULL) {
52 return NULL;
53 }
54 Object *root = make_pair(next_obj, obj_nil);
55 Object *list = root;
56 while (tokens->n > 0 && (next_obj = parse(tokens)) != NULL) {
57 list->cdr = make_pair(next_obj, obj_nil);
58 list = list->cdr;
59 }
60 return root;
61 } break;
62 case TOKEN_STRING: {
63 Object *obj = make_empty_string();
64 append_string(obj, token->value);
65 return obj;
66 } break;
67 case TOKEN_SYMBOL: {
68 return make_symbol(token->value.start, token->value.n);
69 } break;
70 default: {
71 fprintf(stderr, "error: unknown token\n");
72 } break;
73 }
74 }
75
76 return NULL;
77}
78
diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c
new file mode 100644
index 0000000..50a2dfb
--- /dev/null
+++ b/src/bootstrap/primitives.c
@@ -0,0 +1,151 @@
1void
2display(Object *root) {
3 if (root == NULL) {
4 return;
5 }
6
7 switch (root->type) {
8 case OBJ_TYPE_FIXNUM: {
9 printf("%zd", root->fixnum);
10 } break;
11 case OBJ_TYPE_BOOL: {
12 if (root->boolean) {
13 printf("true");
14 } else {
15 printf("false");
16 }
17 } break;
18 case OBJ_TYPE_NIL: {
19 printf("()");
20 } break;
21 case OBJ_TYPE_STRING: {
22 printf("\"%.*s\"", (int)root->string_n, root->string);
23 } break;
24 case OBJ_TYPE_SYMBOL: {
25 printf(":%.*s", (int)root->symbol_n, root->symbol);
26 } break;
27 case OBJ_TYPE_PAIR: {
28 printf("(");
29 display_pair(root);
30 printf(")");
31 } break;
32 default: {
33 printf("TYPE NOT IMPLEMENTED FOR DISPLAY.");
34 } break;
35 }
36}
37
38Object *
39eval(Object *root) {
40 if (root == NULL) {
41 return NULL;
42 }
43
44 switch (root->type) {
45 case OBJ_TYPE_FIXNUM:
46 case OBJ_TYPE_BOOL:
47 case OBJ_TYPE_NIL:
48 case OBJ_TYPE_STRING:
49 case OBJ_TYPE_SYMBOL: {
50 return root;
51 } break;
52 case OBJ_TYPE_PAIR: {
53 if (root->car->type == OBJ_TYPE_SYMBOL) {
54 Object *value = find_environment_symbol(root->car);
55 if (value == NULL) {
56 printf("error: symbol not found: `");
57 display(root->car);
58 printf("`\n");
59 return NULL;
60 }
61 if (value->type == OBJ_TYPE_PROCEDURE) {
62 return value->proc(root->cdr);
63 }
64 }
65 } break;
66 default: {
67 printf("error: can't eval type %d.\n", root->type);
68 } break;
69 }
70
71 return NULL;
72}
73
74Object *
75proc_add(Object *args) {
76 ssize_t tot = 0;
77 while (args->type == OBJ_TYPE_PAIR) {
78 Object *car = eval(args->car);
79 if (car->type != OBJ_TYPE_FIXNUM) {
80 fprintf(stderr, "addition not supported for type %d\n", car->type);
81 return NULL;
82 }
83 tot += car->fixnum;
84 args = args->cdr;
85 }
86 return make_fixnum(tot);
87}
88
89Object *
90proc_sub(Object *args) {
91 if (args->type != OBJ_TYPE_PAIR) {
92 fprintf(stderr, "substraction not supported for type %d\n", args->type);
93 return NULL;
94 }
95
96 // Extract first parameter.
97 Object *car = eval(args->car);
98 args = args->cdr;
99 ssize_t tot = car->fixnum;
100
101 while (args->type == OBJ_TYPE_PAIR) {
102 Object *car = eval(args->car);
103 if (car->type != OBJ_TYPE_FIXNUM) {
104 fprintf(stderr, "substraction not supported for type %d\n", car->type);
105 return NULL;
106 }
107 tot -= car->fixnum;
108 args = args->cdr;
109 }
110 return make_fixnum(tot);
111}
112
113Object *
114proc_mul(Object *args) {
115 ssize_t tot = 1;
116 while (args->type == OBJ_TYPE_PAIR) {
117 Object *car = eval(args->car);
118 if (car->type != OBJ_TYPE_FIXNUM) {
119 fprintf(stderr, "multiply not supported for type %d\n", car->type);
120 return NULL;
121 }
122 tot *= car->fixnum;
123 args = args->cdr;
124 }
125 return make_fixnum(tot);
126}
127
128Object *
129proc_div(Object *args) {
130 if (args->type != OBJ_TYPE_PAIR) {
131 fprintf(stderr, "substraction not supported for type %d\n", args->type);
132 return NULL;
133 }
134
135 // Extract first parameter.
136 Object *car = eval(args->car);
137 args = args->cdr;
138 ssize_t tot = car->fixnum;
139
140 while (args->type == OBJ_TYPE_PAIR) {
141 Object *car = eval(args->car);
142 if (car->type != OBJ_TYPE_FIXNUM) {
143 fprintf(stderr, "div not supported for type %d\n", car->type);
144 return NULL;
145 }
146 tot /= car->fixnum;
147 args = args->cdr;
148 }
149 return make_fixnum(tot);
150}
151
diff --git a/src/bootstrap/readline.c b/src/bootstrap/readline.c
new file mode 100644
index 0000000..dfd8285
--- /dev/null
+++ b/src/bootstrap/readline.c
@@ -0,0 +1,28 @@
1#define READLINE_VALID_CHAR(C) (((u8)(C) >= 0x20 && (u8)(C) < 0x7F) || (C) == '\n')
2
3StringView
4read_line(FILE *fd, char delimiter) {
5 #define RL_BUF_SIZE 1024
6 static char readline_buf[RL_BUF_SIZE];
7
8 // Clear buffer.
9 for (size_t i = 0; i < RL_BUF_SIZE; i++) {
10 readline_buf[i] = 0;
11 }
12
13 // Barebones readline implementation.
14 size_t n = 0;
15 char c;
16 while ((c = getc(fd)) != delimiter) {
17 if (c == '\b') {
18 readline_buf[n] = '\0';
19 n--;
20 } else if (READLINE_VALID_CHAR(c) && n < RL_BUF_SIZE) {
21 readline_buf[n] = c;
22 n++;
23 }
24 }
25
26 return (StringView){.start = (char *)&readline_buf, .n = n};
27}
28
diff --git a/src/bootstrap/string_view.c b/src/bootstrap/string_view.c
new file mode 100644
index 0000000..3cf275a
--- /dev/null
+++ b/src/bootstrap/string_view.c
@@ -0,0 +1,25 @@
1typedef struct StringView {
2 char *start;
3 size_t n;
4} StringView;
5
6void
7sv_write(StringView sv) {
8 for (size_t i = 0; i < sv.n; i++) {
9 putchar(sv.start[i]);
10 }
11}
12
13bool
14sv_equal(StringView a, StringView b) {
15 if (a.n == b.n) {
16 for (size_t i = 0; i < a.n; i++) {
17 if (a.start[i] != b.start[i]) {
18 return false;
19 }
20 }
21 return true;
22 }
23 return false;
24}
25