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