GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/lbm_c_interop.c
Date: 2025-10-27 19:12:55
Exec Total Coverage
Lines: 54 143 37.8%
Functions: 7 20 35.0%
Branches: 16 82 19.5%

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