diff options
-rw-r--r-- | src/ir.h | 53 | ||||
-rw-r--r-- | src/parser.c | 62 | ||||
-rw-r--r-- | src/parser.h | 31 |
3 files changed, 108 insertions, 38 deletions
@@ -115,34 +115,43 @@ proc_alloc(ProgramIr *program, StringView name) { | |||
115 | void compile_object(ProgramIr *program, Procedure *proc, Object *obj); | 115 | void compile_object(ProgramIr *program, Procedure *proc, Object *obj); |
116 | 116 | ||
117 | void | 117 | void |
118 | compile_arithmetic_list(ProgramIr *program, Procedure *proc, Op op, Object *obj) { | 118 | compile_arithmetic(ProgramIr *program, Procedure *proc, Op op, |
119 | size_t op_line = obj->head->line; | 119 | size_t line, size_t col, Object *args) { |
120 | size_t op_col = obj->head->col; | 120 | compile_object(program, proc, args->head); |
121 | obj = obj->tail; | 121 | args = args->tail; |
122 | 122 | while (args != NULL) { | |
123 | compile_object(program, proc, obj->head); | 123 | compile_object(program, proc, args->head); |
124 | obj = obj->tail; | 124 | args = args->tail; |
125 | while (obj != NULL) { | 125 | Instruction inst = (Instruction){op, NULL, line, col}; |
126 | compile_object(program, proc, obj->head); | ||
127 | obj = obj->tail; | ||
128 | Instruction inst = (Instruction){op, NULL, op_line, op_col}; | ||
129 | array_push(proc->instructions, inst); | 126 | array_push(proc->instructions, inst); |
130 | } | 127 | } |
131 | } | 128 | } |
132 | 129 | ||
133 | void | 130 | void |
134 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { | 131 | compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { |
135 | // TODO: Handle this on the parser? | 132 | size_t line = obj->line; |
136 | if (sv_equal(&obj->head->text, &STRING("+"))) { | 133 | size_t col = obj->col; |
137 | compile_arithmetic_list(program, proc, OP_ADD, obj); | 134 | if (obj->head->type == OBJ_TYPE_BUILTIN) { |
138 | } else if (sv_equal(&obj->head->text, &STRING("-"))) { | 135 | switch (obj->head->builtin) { |
139 | compile_arithmetic_list(program, proc, OP_SUB, obj); | 136 | case BUILTIN_ADD: { |
140 | } else if (sv_equal(&obj->head->text, &STRING("*"))) { | 137 | compile_arithmetic(program, proc, OP_ADD, line, col, obj->tail); |
141 | compile_arithmetic_list(program, proc, OP_MUL, obj); | 138 | } break; |
142 | } else if (sv_equal(&obj->head->text, &STRING("/"))) { | 139 | case BUILTIN_SUB: { |
143 | compile_arithmetic_list(program, proc, OP_DIV, obj); | 140 | compile_arithmetic(program, proc, OP_SUB, line, col, obj->tail); |
144 | } else if (sv_equal(&obj->head->text, &STRING("%"))) { | 141 | } break; |
145 | compile_arithmetic_list(program, proc, OP_MOD, obj); | 142 | case BUILTIN_MUL: { |
143 | compile_arithmetic(program, proc, OP_MUL, line, col, obj->tail); | ||
144 | } break; | ||
145 | case BUILTIN_DIV: { | ||
146 | compile_arithmetic(program, proc, OP_DIV, line, col, obj->tail); | ||
147 | } break; | ||
148 | case BUILTIN_MOD: { | ||
149 | compile_arithmetic(program, proc, OP_MOD, line, col, obj->tail); | ||
150 | } break; | ||
151 | default: { | ||
152 | assert(false && "builtin not implemented"); | ||
153 | } break; | ||
154 | } | ||
146 | } else { | 155 | } else { |
147 | assert(false && "compile_proc_call: not implemented"); | 156 | assert(false && "compile_proc_call: not implemented"); |
148 | } | 157 | } |
diff --git a/src/parser.c b/src/parser.c index e72675f..298220a 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -5,7 +5,7 @@ static Object **objects = NULL; | |||
5 | static Root *roots = NULL; | 5 | static Root *roots = NULL; |
6 | static Environment **environments = NULL; | 6 | static Environment **environments = NULL; |
7 | 7 | ||
8 | static char *builtins [] = { | 8 | static char *builtin_names[] = { |
9 | "+", "-", "*", "/", "%", | 9 | "+", "-", "*", "/", "%", |
10 | "=", "<", ">", "<=", ">=", | 10 | "=", "<", ">", "<=", ">=", |
11 | "not", "and", "or", | 11 | "not", "and", "or", |
@@ -14,6 +14,30 @@ static char *builtins [] = { | |||
14 | "cons", "car", "cdr", | 14 | "cons", "car", "cdr", |
15 | }; | 15 | }; |
16 | 16 | ||
17 | static Object builtins[] = { | ||
18 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_ADD } , | ||
19 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_SUB } , | ||
20 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_MUL } , | ||
21 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_DIV } , | ||
22 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_MOD } , | ||
23 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_EQ } , | ||
24 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_LT } , | ||
25 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_GT } , | ||
26 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_LE } , | ||
27 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_GE } , | ||
28 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_NOT } , | ||
29 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_AND } , | ||
30 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_OR } , | ||
31 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_NIL } , | ||
32 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_ZERO } , | ||
33 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_FIXNUM } , | ||
34 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_BOOL } , | ||
35 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_PRINT } , | ||
36 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CONS } , | ||
37 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CAR } , | ||
38 | { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CDR } , | ||
39 | }; | ||
40 | |||
17 | Token | 41 | Token |
18 | peek_token(const Parser *parser) { | 42 | peek_token(const Parser *parser) { |
19 | if (parser->current >= array_size(parser->tokens)) { | 43 | if (parser->current >= array_size(parser->tokens)) { |
@@ -79,6 +103,16 @@ parse_string(Token tok) { | |||
79 | 103 | ||
80 | Object * | 104 | Object * |
81 | parse_symbol(Token tok) { | 105 | parse_symbol(Token tok) { |
106 | // Check if symbol is a builtin procedure. | ||
107 | size_t n_builtins = sizeof(builtin_names) / sizeof(char*); | ||
108 | for (size_t i = 0; i < n_builtins; ++i) { | ||
109 | char *str = builtin_names[i]; | ||
110 | size_t str_n = strlen(str); | ||
111 | if (sv_equal(&tok.value, &(StringView){str, str_n})) { | ||
112 | return &builtins[i]; | ||
113 | } | ||
114 | } | ||
115 | |||
82 | Object *ret = object_alloc(tok, OBJ_TYPE_SYMBOL); | 116 | Object *ret = object_alloc(tok, OBJ_TYPE_SYMBOL); |
83 | ret->text = tok.value; | 117 | ret->text = tok.value; |
84 | return ret; | 118 | return ret; |
@@ -352,7 +386,9 @@ parse_list(Parser *parser, Errors *errors) { | |||
352 | } | 386 | } |
353 | 387 | ||
354 | if (first) { | 388 | if (first) { |
355 | if (!IS_SYMBOL(current->head) && !IS_LAMBDA(current->head)) { | 389 | if (!IS_SYMBOL(current->head) && |
390 | !IS_LAMBDA(current->head) && | ||
391 | !IS_BUILTIN(current->head)) { | ||
356 | error_push(errors, (Error){ | 392 | error_push(errors, (Error){ |
357 | .type = ERR_TYPE_PARSER, | 393 | .type = ERR_TYPE_PARSER, |
358 | .value = ERR_NOT_CALLABLE, | 394 | .value = ERR_NOT_CALLABLE, |
@@ -613,20 +649,8 @@ parse(Token *tokens, Errors *errors) { | |||
613 | array_push(roots, root); | 649 | array_push(roots, root); |
614 | } | 650 | } |
615 | 651 | ||
616 | // Prepare global environment of builtin functions. | 652 | // Prepare global environment. |
617 | Environment *global_env = env_alloc(NULL); | 653 | Environment *env = env_alloc(NULL); |
618 | Environment *env = env_alloc(global_env); | ||
619 | size_t n_builtins = sizeof(builtins) / sizeof(char*); | ||
620 | for (size_t i = 0; i < n_builtins; i++) { | ||
621 | // Prepare builtin symbol. | ||
622 | char *str = builtins[i]; | ||
623 | size_t str_n = strlen(str); | ||
624 | Object *symbol = object_alloc((Token){0}, OBJ_TYPE_SYMBOL); | ||
625 | symbol->text = (StringView){str, str_n}; | ||
626 | |||
627 | // Insert in global table. | ||
628 | insert_local(global_env, symbol, symbol); | ||
629 | } | ||
630 | 654 | ||
631 | // Perform semantic analysis: | 655 | // Perform semantic analysis: |
632 | // 1. Populate symbol tables and ensure symbols are in scope when used. | 656 | // 1. Populate symbol tables and ensure symbols are in scope when used. |
@@ -807,6 +831,9 @@ object_display(Object *obj) { | |||
807 | object_display(obj->var_expr); | 831 | object_display(obj->var_expr); |
808 | printf(" }"); | 832 | printf(" }"); |
809 | } break; | 833 | } break; |
834 | case OBJ_TYPE_BUILTIN: { | ||
835 | printf("%s", builtin_names[obj->builtin]); | ||
836 | } break; | ||
810 | } | 837 | } |
811 | return; | 838 | return; |
812 | } | 839 | } |
@@ -828,6 +855,9 @@ object_equal(Object *a, Object *b) { | |||
828 | case OBJ_TYPE_STRING: { | 855 | case OBJ_TYPE_STRING: { |
829 | return sv_equal(&a->text, &b->text); | 856 | return sv_equal(&a->text, &b->text); |
830 | } break; | 857 | } break; |
858 | case OBJ_TYPE_BUILTIN: { | ||
859 | return a->builtin = b->builtin; | ||
860 | } break; | ||
831 | default: break; | 861 | default: break; |
832 | } | 862 | } |
833 | return false; | 863 | return false; |
diff --git a/src/parser.h b/src/parser.h index 60a307c..41f1fc1 100644 --- a/src/parser.h +++ b/src/parser.h | |||
@@ -23,8 +23,33 @@ typedef enum ObjectType { | |||
23 | OBJ_TYPE_IF, | 23 | OBJ_TYPE_IF, |
24 | OBJ_TYPE_DEF, | 24 | OBJ_TYPE_DEF, |
25 | OBJ_TYPE_SET, | 25 | OBJ_TYPE_SET, |
26 | OBJ_TYPE_BUILTIN, | ||
26 | } ObjectType; | 27 | } ObjectType; |
27 | 28 | ||
29 | typedef enum Builtin { | ||
30 | BUILTIN_ADD, | ||
31 | BUILTIN_SUB, | ||
32 | BUILTIN_MUL, | ||
33 | BUILTIN_DIV, | ||
34 | BUILTIN_MOD, | ||
35 | BUILTIN_EQ, | ||
36 | BUILTIN_LT, | ||
37 | BUILTIN_GT, | ||
38 | BUILTIN_LE, | ||
39 | BUILTIN_GE, | ||
40 | BUILTIN_NOT, | ||
41 | BUILTIN_AND, | ||
42 | BUILTIN_OR, | ||
43 | BUILTIN_IS_NIL, | ||
44 | BUILTIN_IS_ZERO, | ||
45 | BUILTIN_IS_FIXNUM, | ||
46 | BUILTIN_IS_BOOL, | ||
47 | BUILTIN_IS_PRINT, | ||
48 | BUILTIN_IS_CONS, | ||
49 | BUILTIN_IS_CAR, | ||
50 | BUILTIN_IS_CDR, | ||
51 | } Builtin; | ||
52 | |||
28 | typedef struct Object { | 53 | typedef struct Object { |
29 | ObjectType type; | 54 | ObjectType type; |
30 | union { | 55 | union { |
@@ -62,6 +87,11 @@ typedef struct Object { | |||
62 | struct Object *var_name; | 87 | struct Object *var_name; |
63 | struct Object *var_expr; | 88 | struct Object *var_expr; |
64 | }; | 89 | }; |
90 | |||
91 | // OBJ_TYPE_BUILTIN | ||
92 | struct { | ||
93 | Builtin builtin; | ||
94 | }; | ||
65 | }; | 95 | }; |
66 | 96 | ||
67 | bool visited; | 97 | bool visited; |
@@ -125,6 +155,7 @@ void free_objects(void); | |||
125 | #define IS_SYMBOL(VAL) ((VAL)->type == OBJ_TYPE_SYMBOL) | 155 | #define IS_SYMBOL(VAL) ((VAL)->type == OBJ_TYPE_SYMBOL) |
126 | #define IS_PAIR(VAL) ((VAL)->type == OBJ_TYPE_PAIR) | 156 | #define IS_PAIR(VAL) ((VAL)->type == OBJ_TYPE_PAIR) |
127 | #define IS_LAMBDA(VAL) ((VAL)->type == OBJ_TYPE_LAMBDA) | 157 | #define IS_LAMBDA(VAL) ((VAL)->type == OBJ_TYPE_LAMBDA) |
158 | #define IS_BUILTIN(VAL) ((VAL)->type == OBJ_TYPE_BUILTIN) | ||
128 | 159 | ||
129 | // Debug. | 160 | // Debug. |
130 | #define OBJ_PRINT(OBJ) object_display(OBJ); printf("\n"); | 161 | #define OBJ_PRINT(OBJ) object_display(OBJ); printf("\n"); |