GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_c_interop.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 135 147 91.8%
Functions: 20 20 100.0%
Branches: 60 86 69.8%

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