Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | Copyright 2022 Joel Svensson svenssonjoel@yahoo.se | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "lbm_c_interop.h" | ||
19 | |||
20 | /****************************************************/ | ||
21 | /* Interface for loading and running programs and */ | ||
22 | /* expressions */ | ||
23 | |||
24 | 17444 | lbm_cid eval_cps_load_and_eval(lbm_char_channel_t *tokenizer, bool program, bool incremental, char *name) { | |
25 | |||
26 | lbm_value stream; | ||
27 | |||
28 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17444 times.
|
17444 | if (!lift_char_channel(tokenizer, &stream)) { |
29 | ✗ | return 0; | |
30 | } | ||
31 | |||
32 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17444 times.
|
17444 | if (lbm_type_of(stream) == LBM_TYPE_SYMBOL) { |
33 | // TODO: Check what should be done. | ||
34 | ✗ | return 0; | |
35 | } | ||
36 | |||
37 | 17444 | lbm_value read_mode = ENC_SYM_READ; | |
38 |
1/2✓ Branch 0 taken 17444 times.
✗ Branch 1 not taken.
|
17444 | if (program) { |
39 |
2/2✓ Branch 0 taken 8722 times.
✓ Branch 1 taken 8722 times.
|
17444 | if (incremental) { |
40 | 8722 | read_mode = ENC_SYM_READ_AND_EVAL_PROGRAM; | |
41 | } else { | ||
42 | 8722 | read_mode = ENC_SYM_READ_PROGRAM; | |
43 | } | ||
44 | } | ||
45 | /* | ||
46 | read-eval-program finishes with the result of the final expression in | ||
47 | the program. This should not be passed to eval-program as it is most likely | ||
48 | not a program. Even if it is a program, its not one we want to evaluate. | ||
49 | */ | ||
50 | |||
51 | /* LISP ZONE */ | ||
52 | 17444 | lbm_value launcher = lbm_cons(stream, ENC_SYM_NIL); | |
53 | 17444 | launcher = lbm_cons(read_mode, launcher); | |
54 | lbm_value evaluator; | ||
55 | lbm_value start_prg; | ||
56 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17444 times.
|
17444 | if (read_mode == ENC_SYM_READ) { |
57 | ✗ | evaluator = lbm_cons(launcher, ENC_SYM_NIL); | |
58 | ✗ | evaluator = lbm_cons(ENC_SYM_EVAL, evaluator); | |
59 | ✗ | start_prg = lbm_cons(evaluator, ENC_SYM_NIL); | |
60 |
2/2✓ Branch 0 taken 8722 times.
✓ Branch 1 taken 8722 times.
|
17444 | } else if (read_mode == ENC_SYM_READ_PROGRAM) { |
61 | 8722 | evaluator = lbm_cons(launcher, ENC_SYM_NIL); | |
62 | 8722 | evaluator = lbm_cons(ENC_SYM_EVAL_PROGRAM, evaluator); | |
63 | 8722 | start_prg = lbm_cons(evaluator, ENC_SYM_NIL); | |
64 | } else { // ENC_SYM_READ_AND_EVAL_PROGRAM | ||
65 | 8722 | evaluator = launcher; // dummy so check below passes | |
66 | 8722 | start_prg = lbm_cons(launcher, ENC_SYM_NIL); | |
67 | } | ||
68 | |||
69 | /* LISP ZONE ENDS */ | ||
70 | |||
71 |
2/4✓ Branch 1 taken 17444 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 17444 times.
✗ Branch 4 not taken.
|
34888 | if (lbm_type_of(launcher) != LBM_TYPE_CONS || |
72 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17444 times.
|
34888 | lbm_type_of(evaluator) != LBM_TYPE_CONS || |
73 | 17444 | lbm_type_of(start_prg) != LBM_TYPE_CONS ) { | |
74 | //lbm_explicit_free_token_stream(stream); | ||
75 | ✗ | return 0; | |
76 | } | ||
77 | 17444 | return lbm_create_ctx(start_prg, ENC_SYM_NIL, 256, name); | |
78 | } | ||
79 | |||
80 | ✗ | lbm_cid eval_cps_load_and_define(lbm_char_channel_t *tokenizer, char *symbol, bool program) { | |
81 | |||
82 | lbm_value stream; | ||
83 | |||
84 | ✗ | if (!lift_char_channel(tokenizer, &stream)) { | |
85 | ✗ | return 0; | |
86 | } | ||
87 | |||
88 | ✗ | if (lbm_type_of(stream) == LBM_TYPE_SYMBOL) { | |
89 | ✗ | return 0; | |
90 | } | ||
91 | |||
92 | lbm_uint sym_id; | ||
93 | |||
94 | ✗ | if (!lbm_get_symbol_by_name(symbol, &sym_id)) { | |
95 | ✗ | if (!lbm_add_symbol_base(symbol, &sym_id,false)) { //ram | |
96 | //lbm_explicit_free_token_stream(stream); | ||
97 | ✗ | return 0; | |
98 | } | ||
99 | } | ||
100 | |||
101 | /* LISP ZONE */ | ||
102 | |||
103 | ✗ | lbm_value launcher = lbm_cons(stream, lbm_enc_sym(SYM_NIL)); | |
104 | ✗ | launcher = lbm_cons(lbm_enc_sym(program ? SYM_READ_PROGRAM : SYM_READ), launcher); | |
105 | ✗ | lbm_value binding = lbm_cons(launcher, lbm_enc_sym(SYM_NIL)); | |
106 | ✗ | binding = lbm_cons(lbm_enc_sym(sym_id), binding); | |
107 | ✗ | lbm_value definer = lbm_cons(lbm_enc_sym(SYM_DEFINE), binding); | |
108 | ✗ | definer = lbm_cons(definer, lbm_enc_sym(SYM_NIL)); | |
109 | /* LISP ZONE ENDS */ | ||
110 | |||
111 | ✗ | if (lbm_type_of(launcher) != LBM_TYPE_CONS || | |
112 | ✗ | lbm_type_of(binding) != LBM_TYPE_CONS || | |
113 | ✗ | lbm_type_of(definer) != LBM_TYPE_CONS ) { | |
114 | //lbm_explicit_free_token_stream(stream); | ||
115 | ✗ | return 0; | |
116 | } | ||
117 | ✗ | return lbm_create_ctx(definer, lbm_enc_sym(SYM_NIL), 256, NULL); | |
118 | } | ||
119 | |||
120 | ✗ | lbm_cid lbm_eval_defined(char *symbol, bool program) { | |
121 | |||
122 | lbm_uint sym_id; | ||
123 | |||
124 | ✗ | if(!lbm_get_symbol_by_name(symbol, &sym_id)) { | |
125 | // The symbol does not exist, so it cannot be defined | ||
126 | ✗ | return 0; | |
127 | } | ||
128 | |||
129 | lbm_value binding; | ||
130 | |||
131 | ✗ | if (!lbm_global_env_lookup(&binding, lbm_enc_sym(sym_id))) { | |
132 | ✗ | return 0; | |
133 | } | ||
134 | |||
135 | /* LISP ZONE */ | ||
136 | |||
137 | ✗ | lbm_value launcher = lbm_cons(lbm_enc_sym(sym_id), lbm_enc_sym(SYM_NIL)); | |
138 | ✗ | lbm_value evaluator = launcher; | |
139 | ✗ | evaluator = lbm_cons(lbm_enc_sym(program ? SYM_EVAL_PROGRAM : SYM_EVAL), evaluator); | |
140 | ✗ | lbm_value start_prg = lbm_cons(evaluator, lbm_enc_sym(SYM_NIL)); | |
141 | |||
142 | /* LISP ZONE ENDS */ | ||
143 | |||
144 | ✗ | if (lbm_type_of(launcher) != LBM_TYPE_CONS || | |
145 | ✗ | lbm_type_of(evaluator) != LBM_TYPE_CONS || | |
146 | ✗ | lbm_type_of(start_prg) != LBM_TYPE_CONS ) { | |
147 | ✗ | return 0; | |
148 | } | ||
149 | ✗ | return lbm_create_ctx(start_prg, lbm_enc_sym(SYM_NIL), 256, NULL); | |
150 | } | ||
151 | |||
152 | |||
153 | |||
154 | ✗ | lbm_cid lbm_load_and_eval_expression(lbm_char_channel_t *tokenizer) { | |
155 | ✗ | return eval_cps_load_and_eval(tokenizer, false,false, NULL); | |
156 | } | ||
157 | |||
158 | ✗ | lbm_cid lbm_load_and_define_expression(lbm_char_channel_t *tokenizer, char *symbol) { | |
159 | ✗ | return eval_cps_load_and_define(tokenizer, symbol, false); | |
160 | } | ||
161 | |||
162 | 8722 | lbm_cid lbm_load_and_eval_program(lbm_char_channel_t *tokenizer, char *name) { | |
163 | 8722 | return eval_cps_load_and_eval(tokenizer, true, false, name); | |
164 | } | ||
165 | |||
166 | 8722 | lbm_cid lbm_load_and_eval_program_incremental(lbm_char_channel_t *tokenizer, char *name) { | |
167 | 8722 | return eval_cps_load_and_eval(tokenizer, true, true, name); | |
168 | } | ||
169 | |||
170 | ✗ | lbm_cid lbm_load_and_define_program(lbm_char_channel_t *tokenizer, char *symbol) { | |
171 | ✗ | return eval_cps_load_and_define(tokenizer, symbol, true); | |
172 | } | ||
173 | |||
174 | ✗ | lbm_cid lbm_eval_defined_expression(char *symbol) { | |
175 | ✗ | return lbm_eval_defined(symbol, false); | |
176 | } | ||
177 | |||
178 | ✗ | lbm_cid lbm_eval_defined_program(char *symbol) { | |
179 | ✗ | return lbm_eval_defined(symbol, true); | |
180 | } | ||
181 | |||
182 | ✗ | int lbm_send_message(lbm_cid cid, lbm_value msg) { | |
183 | ✗ | int res = 0; | |
184 | |||
185 | ✗ | if (lbm_get_eval_state() == EVAL_CPS_STATE_PAUSED) { | |
186 | |||
187 | ✗ | lbm_value v = lbm_find_receiver_and_send(cid, msg); | |
188 | |||
189 | ✗ | if (lbm_type_of(v) == LBM_TYPE_SYMBOL && | |
190 | ✗ | lbm_dec_sym(v) == SYM_TRUE) { | |
191 | ✗ | res = 1; | |
192 | } | ||
193 | } | ||
194 | ✗ | return res; | |
195 | } | ||
196 | |||
197 | ✗ | int lbm_define(char *symbol, lbm_value value) { | |
198 | ✗ | int res = 0; | |
199 | |||
200 | lbm_uint sym_id; | ||
201 | ✗ | if (lbm_get_eval_state() == EVAL_CPS_STATE_PAUSED) { | |
202 | ✗ | if (!lbm_get_symbol_by_name(symbol, &sym_id)) { | |
203 | ✗ | if (!lbm_add_symbol_const_base(symbol, &sym_id)) { | |
204 | ✗ | return 0; | |
205 | } | ||
206 | } | ||
207 | ✗ | lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; | |
208 | ✗ | lbm_value *glob_env = lbm_get_global_env(); | |
209 | ✗ | glob_env[ix_key] = lbm_env_set(glob_env[ix_key], lbm_enc_sym(sym_id), value); | |
210 | } | ||
211 | ✗ | return res; | |
212 | } | ||
213 | |||
214 | ✗ | int lbm_undefine(char *symbol) { | |
215 | lbm_uint sym_id; | ||
216 | ✗ | if (!lbm_get_symbol_by_name(symbol, &sym_id)) | |
217 | ✗ | return 0; | |
218 | |||
219 | ✗ | lbm_value *glob_env = lbm_get_global_env(); | |
220 | ✗ | lbm_uint ix_key = sym_id & GLOBAL_ENV_MASK; | |
221 | ✗ | lbm_value new_env = lbm_env_drop_binding(glob_env[ix_key], lbm_enc_sym(sym_id)); | |
222 | |||
223 | ✗ | if (new_env == ENC_SYM_NOT_FOUND) return 0; | |
224 | ✗ | glob_env[ix_key] = new_env; | |
225 | ✗ | return 1; | |
226 | } | ||
227 | |||
228 | ✗ | int lbm_share_array(lbm_value *value, char *data, lbm_uint num_elt) { | |
229 | ✗ | return lbm_lift_array(value, data, num_elt); | |
230 | } | ||
231 | |||
232 | 112 | static bool share_const_array(lbm_value flash_cell, char *data, lbm_uint num_elt) { | |
233 | lbm_array_header_t flash_array_header; | ||
234 | 112 | flash_array_header.size = num_elt; | |
235 | 112 | flash_array_header.data = (lbm_uint*)data; | |
236 | lbm_uint flash_array_header_ptr; | ||
237 | 112 | lbm_flash_status s = lbm_write_const_raw((lbm_uint*)&flash_array_header, | |
238 | sizeof(lbm_array_header_t) / sizeof(lbm_uint), | ||
239 | &flash_array_header_ptr); | ||
240 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | if (s != LBM_FLASH_WRITE_OK) return false; |
241 | 112 | s = write_const_car(flash_cell, flash_array_header_ptr); | |
242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | if (s != LBM_FLASH_WRITE_OK) return false; |
243 | 112 | s = write_const_cdr(flash_cell, ENC_SYM_ARRAY_TYPE); | |
244 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | if (s != LBM_FLASH_WRITE_OK) return false; |
245 | 112 | return true; | |
246 | } | ||
247 | |||
248 | 112 | int lbm_share_const_array(lbm_value *res, char *flash_ptr, lbm_uint num_elt) { | |
249 | 112 | lbm_value arr = 0; | |
250 | 112 | arr = LBM_PTR_BIT | LBM_TYPE_ARRAY; | |
251 | |||
252 | 112 | lbm_value flash_arr = 0; | |
253 | 112 | lbm_flash_status r = request_flash_storage_cell(arr, &flash_arr); | |
254 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | if (r == LBM_FLASH_WRITE_OK) { |
255 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
|
112 | if (!share_const_array(flash_arr, flash_ptr, num_elt)) { |
256 | ✗ | return 0; | |
257 | } | ||
258 | } | ||
259 | |||
260 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | if (r == LBM_FLASH_WRITE_OK) { |
261 | 112 | *res = flash_arr; | |
262 | 112 | return 1; | |
263 | } | ||
264 | ✗ | return 0; | |
265 | } | ||
266 | |||
267 | 136420 | int lbm_create_array(lbm_value *value, lbm_uint num_elt) { | |
268 | 136420 | return lbm_heap_allocate_array(value, num_elt); | |
269 | } | ||
270 | |||
271 | |||
272 | ✗ | void lbm_clear_env(void) { | |
273 | |||
274 | ✗ | lbm_value *env = lbm_get_global_env(); | |
275 | ✗ | for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) { | |
276 | ✗ | env[i] = ENC_SYM_NIL; | |
277 | } | ||
278 | ✗ | lbm_perform_gc(); | |
279 | ✗ | } | |
280 | |||
281 | // Evaluator should be paused when running this. | ||
282 | // Running gc will reclaim the fv storage. | ||
283 | ✗ | bool lbm_flatten_env(int index, lbm_uint** data, lbm_uint *size) { | |
284 | ✗ | if (index < 0 || index >= GLOBAL_ENV_ROOTS) return false; | |
285 | ✗ | lbm_value *env = lbm_get_global_env(); | |
286 | |||
287 | ✗ | lbm_value fv = flatten_value(env[index]); | |
288 | |||
289 | ✗ | if (lbm_is_symbol(fv)) return false; | |
290 | |||
291 | ✗ | lbm_array_header_t *array = (lbm_array_header_t *)lbm_car(fv); | |
292 | ✗ | *size = array->size; | |
293 | ✗ | *data = array->data; | |
294 | ✗ | return true; | |
295 | } | ||
296 |