-
Notifications
You must be signed in to change notification settings - Fork 6
/
compile.c
146 lines (129 loc) · 4.28 KB
/
compile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "toy.h"
#include <errno.h>
static value_t v_die(value_t ctx, value_t message) {
(void)ctx;
die(v_to_string(message));
}
static value_t v_print(value_t ctx, value_t message) {
(void)ctx;
char *s = v_to_string(message);
puts(s);
free(s);
return v_null;
}
static value_t v_parse_int(value_t ctx, value_t vstring) {
(void)ctx;
char *endptr;
char *s = v_to_string(vstring);
errno = 0;
long number = strtol(s, &endptr, 10);
if (errno || *endptr) {
free(s);
return v_null;
}
free(s);
return v_number(number);
}
static value_t v_math_floor(value_t ctx, value_t number) {
(void)ctx;
return v_number(v_to_integer(number));
}
static value_t get_math(void) {
value_t m = v_dict();
v_set(m, v_string("floor"), v_native_func(v_math_floor));
return m;
}
static value_t get_global_scope(void) {
value_t scope = v_dict();
v_set(scope, v_string("die"), v_native_func(v_die));
v_set(scope, v_string("print"), v_native_func(v_print));
v_set(scope, v_string("parseInt"), v_native_func(v_parse_int));
v_set(scope, v_string("Math"), get_math());
return scope;
}
static value_t import_nodejs_module(value_t file_func, value_t global_scope) {
value_t exports = v_dict();
value_t module = v_dict();
v_set(module, v_string("exports"), exports);
v_set(global_scope, v_string("module"), module);
eval_func(file_func, global_scope);
return v_get(module, v_string("exports"));
}
static value_t get_builtin_file_func(void) {
compiled_file_t *file = get_builtin_file();
value_t vglobal = {
.type = value_type_object,
.object = new_compiled_func_object(file->funcs),
};
return vglobal;
}
static value_t import_builtin_compiler_module(void) {
return import_nodejs_module(get_builtin_file_func(), get_global_scope());
}
static compiled_func_t translate_compiled_func(value_t vfunc) {
value_t vcode = v_get(vfunc, v_string("code"));
value_t vconsts = v_get(vfunc, v_string("consts"));
size_t code_length = v_list_length(vcode);
unsigned char *code = xmalloc(code_length);
size_t const_count = v_list_length(vconsts);
value_t *consts = xmalloc(sizeof(value_t) * const_count);
for (size_t i = 0; i < const_count; i++) {
consts[i] = v_get(vconsts, v_number(i));
}
for (size_t i = 0; i < code_length; i++) {
value_t vinstr = v_get(vcode, v_number(i));
if (v_is_string(vinstr)) {
int opcode = string_to_opcode(vinstr.object->string);
if (opcode == -1) {
die("unknown opcode");
}
code[i] = opcode;
} else {
code[i] = v_to_integer(vinstr);
}
}
return (compiled_func_t){
.param_name = v_to_string(v_get(vfunc, v_string("paramName"))),
.code = code,
.consts = consts,
.const_count = const_count,
};
}
static compiled_file_t *translate_compiled_file(value_t vfuncs) {
compiled_file_t *file = xmalloc(sizeof(compiled_file_t));
file->func_count = v_list_length(vfuncs);
file->funcs = xmalloc(sizeof(compiled_func_t) * file->func_count);
for (size_t i = 0; i < file->func_count; i++) {
value_t vfunc = v_get(vfuncs, v_number(i));
compiled_func_t func = translate_compiled_func(vfunc);
func.file = file;
memcpy(file->funcs + i, &func, sizeof(compiled_func_t));
}
return file;
}
static void free_compiled_file(compiled_file_t *file) {
for (size_t i = 0; i < file->func_count; i++) {
compiled_func_t *func = file->funcs + i;
free(func->code);
free(func->consts);
free(func->param_name);
}
free(file->funcs);
free(file);
}
value_t eval_source(const char *source) {
value_t compile_func = import_builtin_compiler_module();
if (!v_is_func(compile_func)) {
die("the builtin compiler module must export a function");
}
value_t compiled_funcs = call_func(compile_func, v_string(source));
compiled_file_t *file = translate_compiled_file(compiled_funcs);
value_t func = {
.type = value_type_object,
.object = new_compiled_func_object(file->funcs),
};
value_t result = eval_func(func, get_global_scope());
free_compiled_file(file);
collect_garbage();
return result;
}