diff options
-rw-r--r-- | src/ir.h | 113 |
1 files changed, 82 insertions, 31 deletions
@@ -50,12 +50,16 @@ typedef enum Op { | |||
50 | OP_JUMP_IF_GE, | 50 | OP_JUMP_IF_GE, |
51 | OP_JUMP_IF_LE, | 51 | OP_JUMP_IF_LE, |
52 | // Variable access. | 52 | // Variable access. |
53 | // - Require an index corresponding to the local variable to store. | 53 | // - Require an index corresponding to the variable to store. |
54 | // - Consume the last item in the stack. | 54 | // - Consume the last item in the stack. |
55 | OP_STORE_LOCAL, | 55 | OP_STORE_LOCAL, |
56 | // - Require an index corresponding to the local variable to load. | 56 | OP_STORE_CAPTURED, |
57 | OP_STORE_PARAM, | ||
58 | // - Require an index corresponding to the variable to load. | ||
57 | // - The loaded value is pushed into the stack. | 59 | // - The loaded value is pushed into the stack. |
58 | OP_LOAD_LOCAL, | 60 | OP_LOAD_LOCAL, |
61 | OP_LOAD_CAPTURED, | ||
62 | OP_LOAD_PARAM, | ||
59 | // Primitive complex commands. | 63 | // Primitive complex commands. |
60 | // - Prints the last object in the stack. | 64 | // - Prints the last object in the stack. |
61 | OP_PRINT, | 65 | OP_PRINT, |
@@ -69,32 +73,36 @@ typedef enum Op { | |||
69 | } Op; | 73 | } Op; |
70 | 74 | ||
71 | static const char* ops_str[] = { | 75 | static const char* ops_str[] = { |
72 | [OP_ADD] = "OP_ADD", | 76 | [OP_ADD] = "OP_ADD", |
73 | [OP_SUB] = "OP_SUB", | 77 | [OP_SUB] = "OP_SUB", |
74 | [OP_MUL] = "OP_MUL", | 78 | [OP_MUL] = "OP_MUL", |
75 | [OP_DIV] = "OP_DIV", | 79 | [OP_DIV] = "OP_DIV", |
76 | [OP_MOD] = "OP_MOD", | 80 | [OP_MOD] = "OP_MOD", |
77 | [OP_NOT] = "OP_NOT", | 81 | [OP_NOT] = "OP_NOT", |
78 | [OP_PUSH] = "OP_PUSH", | 82 | [OP_PUSH] = "OP_PUSH", |
79 | [OP_DROP] = "OP_DROP", | 83 | [OP_DROP] = "OP_DROP", |
80 | [OP_DUP] = "OP_DUP", | 84 | [OP_DUP] = "OP_DUP", |
81 | [OP_ROT_RIGHT] = "OP_ROT_RIGHT", | 85 | [OP_ROT_RIGHT] = "OP_ROT_RIGHT", |
82 | [OP_ROT_LEFT] = "OP_ROT_LEFT", | 86 | [OP_ROT_LEFT] = "OP_ROT_LEFT", |
83 | [OP_LABEL] = "OP_LABEL", | 87 | [OP_LABEL] = "OP_LABEL", |
84 | [OP_JUMP] = "OP_JUMP", | 88 | [OP_JUMP] = "OP_JUMP", |
85 | [OP_JUMP_IF_TRUE] = "OP_JUMP_IF_TRUE", | 89 | [OP_JUMP_IF_TRUE] = "OP_JUMP_IF_TRUE", |
86 | [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", | 90 | [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", |
87 | [OP_JUMP_IF_EQ] = "OP_JUMP_IF_EQ", | 91 | [OP_JUMP_IF_EQ] = "OP_JUMP_IF_EQ", |
88 | [OP_JUMP_IF_NEQ] = "OP_JUMP_IF_NEQ", | 92 | [OP_JUMP_IF_NEQ] = "OP_JUMP_IF_NEQ", |
89 | [OP_JUMP_IF_GT] = "OP_JUMP_IF_GT", | 93 | [OP_JUMP_IF_GT] = "OP_JUMP_IF_GT", |
90 | [OP_JUMP_IF_LT] = "OP_JUMP_IF_LT", | 94 | [OP_JUMP_IF_LT] = "OP_JUMP_IF_LT", |
91 | [OP_JUMP_IF_GE] = "OP_JUMP_IF_GE", | 95 | [OP_JUMP_IF_GE] = "OP_JUMP_IF_GE", |
92 | [OP_JUMP_IF_LE] = "OP_JUMP_IF_LE", | 96 | [OP_JUMP_IF_LE] = "OP_JUMP_IF_LE", |
93 | [OP_STORE_LOCAL] = "OP_STORE_LOCAL", | 97 | [OP_STORE_LOCAL] = "OP_STORE_LOCAL", |
94 | [OP_LOAD_LOCAL] = "OP_LOAD_LOCAL", | 98 | [OP_STORE_CAPTURED] = "OP_STORE_CAPTURED", |
95 | [OP_PRINT] = "OP_PRINT", | 99 | [OP_STORE_PARAM] = "OP_STORE_PARAM", |
96 | [OP_CALL] = "OP_CALL", | 100 | [OP_LOAD_LOCAL] = "OP_LOAD_LOCAL", |
97 | [OP_RETURN] = "OP_RETURN", | 101 | [OP_LOAD_CAPTURED] = "OP_LOAD_CAPTURED", |
102 | [OP_LOAD_PARAM] = "OP_LOAD_PARAM", | ||
103 | [OP_PRINT] = "OP_PRINT", | ||
104 | [OP_CALL] = "OP_CALL", | ||
105 | [OP_RETURN] = "OP_RETURN", | ||
98 | }; | 106 | }; |
99 | 107 | ||
100 | typedef struct Instruction { | 108 | typedef struct Instruction { |
@@ -129,8 +137,10 @@ typedef struct Procedure { | |||
129 | // Program code. | 137 | // Program code. |
130 | Instruction *instructions; | 138 | Instruction *instructions; |
131 | 139 | ||
132 | // Locals code. | 140 | // Variables. |
133 | Object **locals; | 141 | Object **locals; |
142 | Object **captured; | ||
143 | Object **params; | ||
134 | } Procedure; | 144 | } Procedure; |
135 | 145 | ||
136 | typedef struct ProgramIr { | 146 | typedef struct ProgramIr { |
@@ -185,7 +195,11 @@ print_instruction(Instruction *instruction) { | |||
185 | printf("%-16s -> %zu\n", ops_str[op], instruction->label_id); | 195 | printf("%-16s -> %zu\n", ops_str[op], instruction->label_id); |
186 | } break; | 196 | } break; |
187 | case OP_STORE_LOCAL: | 197 | case OP_STORE_LOCAL: |
188 | case OP_LOAD_LOCAL: { | 198 | case OP_STORE_CAPTURED: |
199 | case OP_STORE_PARAM: | ||
200 | case OP_LOAD_LOCAL: | ||
201 | case OP_LOAD_CAPTURED: | ||
202 | case OP_LOAD_PARAM: { | ||
189 | printf("%-16s -> %zu\n", ops_str[op], instruction->index); | 203 | printf("%-16s -> %zu\n", ops_str[op], instruction->index); |
190 | } break; | 204 | } break; |
191 | default: { | 205 | default: { |
@@ -210,6 +224,8 @@ proc_alloc(ProgramIr *program, StringView name, Procedure *parent) { | |||
210 | array_insert(proc->name, name.start, name.n); | 224 | array_insert(proc->name, name.start, name.n); |
211 | array_init(proc->instructions, 0); | 225 | array_init(proc->instructions, 0); |
212 | array_init(proc->locals, 0); | 226 | array_init(proc->locals, 0); |
227 | array_init(proc->captured, 0); | ||
228 | array_init(proc->params, 0); | ||
213 | proc->parent = parent; | 229 | proc->parent = parent; |
214 | array_push(program->procedures, proc); | 230 | array_push(program->procedures, proc); |
215 | return proc; | 231 | return proc; |
@@ -417,6 +433,13 @@ compile_lambda(ProgramIr *program, Procedure *proc, Object *obj) { | |||
417 | } | 433 | } |
418 | array_push(program->lambdas, obj); | 434 | array_push(program->lambdas, obj); |
419 | Procedure *lambda = proc_alloc(program, STRING("lambda"), proc); | 435 | Procedure *lambda = proc_alloc(program, STRING("lambda"), proc); |
436 | |||
437 | // Parameters. | ||
438 | for (size_t i = 0; i < array_size(obj->params); ++i) { | ||
439 | array_push(lambda->params, obj->params[i]); | ||
440 | } | ||
441 | |||
442 | // Body. | ||
420 | for (size_t i = 0; i < array_size(obj->body) - 1; i++) { | 443 | for (size_t i = 0; i < array_size(obj->body) - 1; i++) { |
421 | compile_object(program, lambda, obj->body[i]); | 444 | compile_object(program, lambda, obj->body[i]); |
422 | } | 445 | } |
@@ -470,6 +493,34 @@ compile_lambda(ProgramIr *program, Procedure *proc, Object *obj) { | |||
470 | } | 493 | } |
471 | 494 | ||
472 | void | 495 | void |
496 | compile_symbol(ProgramIr *program, Procedure *proc, Object *obj) { | ||
497 | ssize_t idx = -1; | ||
498 | |||
499 | // Is a local variable? | ||
500 | idx = find_var_index(proc->locals, obj); | ||
501 | if (idx != -1) { | ||
502 | INST_VAR(proc, OP_LOAD_LOCAL, idx, obj->line, obj->col); | ||
503 | return; | ||
504 | } | ||
505 | |||
506 | // Is a captured variable? | ||
507 | idx = find_var_index(proc->captured, obj); | ||
508 | if (idx != -1) { | ||
509 | INST_VAR(proc, OP_LOAD_CAPTURED, idx, obj->line, obj->col); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | // Is a function parameter? | ||
514 | idx = find_var_index(proc->params, obj); | ||
515 | if (idx != -1) { | ||
516 | INST_VAR(proc, OP_LOAD_PARAM, idx, obj->line, obj->col); | ||
517 | return; | ||
518 | } | ||
519 | |||
520 | assert(idx != -1 && "unexpected index"); | ||
521 | } | ||
522 | |||
523 | void | ||
473 | compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | 524 | compile_object(ProgramIr *program, Procedure *proc, Object *obj) { |
474 | switch (obj->type) { | 525 | switch (obj->type) { |
475 | case OBJ_TYPE_NIL: | 526 | case OBJ_TYPE_NIL: |
@@ -481,7 +532,7 @@ compile_object(ProgramIr *program, Procedure *proc, Object *obj) { | |||
481 | case OBJ_TYPE_IF: { compile_if(program, proc, obj); } break; | 532 | case OBJ_TYPE_IF: { compile_if(program, proc, obj); } break; |
482 | case OBJ_TYPE_LAMBDA: { compile_lambda(program, proc, obj); } break; | 533 | case OBJ_TYPE_LAMBDA: { compile_lambda(program, proc, obj); } break; |
483 | case OBJ_TYPE_DEF: { compile_def(program, proc, obj); } break; | 534 | case OBJ_TYPE_DEF: { compile_def(program, proc, obj); } break; |
484 | // case OBJ_TYPE_SYMBOL: { compile_symbol(obj); } break; | 535 | case OBJ_TYPE_SYMBOL: { compile_symbol(program, proc, obj); } break; |
485 | default: { | 536 | default: { |
486 | // TODO: assert? | 537 | // TODO: assert? |
487 | fprintf(stderr, "NOT IMPLEMENTED: compile_object for "); | 538 | fprintf(stderr, "NOT IMPLEMENTED: compile_object for "); |