GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/symrepr.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 125 130 96.2%
Functions: 21 21 100.0%
Branches: 54 61 88.5%

Line Branch Exec Source
1 /*
2 Copyright 2018, 2021, 2022, 2024, 2025 Joel Svensson svenssonjoel@yahoo.se
3 2025 Rasmus Söderhielm rasmus.soderhielm@gmail.com
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <inttypes.h>
24
25
26 #include <lbm_memory.h>
27 #include <heap.h>
28 #include "symrepr.h"
29 #include "extensions.h"
30 #include "lbm_utils.h"
31 #include "lbm_image.h"
32
33 #define NUM_SPECIAL_SYMBOLS (sizeof(special_symbols) / sizeof(special_sym))
34 #define NAME 0
35 #define ID 1
36 #define NEXT 2
37
38 typedef struct {
39 const char *name;
40 const lbm_uint id;
41 } special_sym;
42
43 special_sym const special_symbols[] = {
44 {"nil" , SYM_NIL},
45 {"quote" , SYM_QUOTE},
46 {"t" , SYM_TRUE},
47 {"if" , SYM_IF},
48 {"cond" , SYM_COND},
49 {"lambda" , SYM_LAMBDA},
50 {"closure" , SYM_CLOSURE},
51 {"let" , SYM_LET},
52 {"define" , SYM_DEFINE},
53 {"progn" , SYM_PROGN},
54 {"read" , SYM_READ},
55 {"read-program" , SYM_READ_PROGRAM},
56 {"read-eval-program", SYM_READ_AND_EVAL_PROGRAM},
57 {"match" , SYM_MATCH},
58 {"_" , SYM_DONTCARE},
59 {"send" , SYM_SEND},
60 {"recv" , SYM_RECEIVE},
61 {"recv-to" , SYM_RECEIVE_TIMEOUT},
62 {"macro" , SYM_MACRO},
63 {"call-cc" , SYM_CALLCC},
64 {"continuation" , SYM_CONT},
65 {"var" , SYM_PROGN_VAR},
66 {"timeout" , SYM_TIMEOUT},
67
68 {"set" , SYM_SETVAR},
69 {"setq" , SYM_SETQ},
70 {"move-to-flash", SYM_MOVE_TO_FLASH},
71 {"exit-ok" , SYM_EXIT_OK},
72 {"exit-error" , SYM_EXIT_ERROR},
73 {"map" , SYM_MAP},
74 {"reverse" , SYM_REVERSE},
75 {"flatten" , SYM_FLATTEN},
76 {"unflatten" , SYM_UNFLATTEN},
77 {"kill" , SYM_KILL},
78 {"sleep" , SYM_SLEEP},
79 {"merge" , SYM_MERGE},
80 {"sort" , SYM_SORT},
81 {"gc" , SYM_PERFORM_GC},
82 {"loop" , SYM_LOOP},
83 {"trap" , SYM_TRAP},
84 {"rest-args" , SYM_REST_ARGS},
85 {"rotate" , SYM_ROTATE},
86 {"call-cc-unsafe", SYM_CALL_CC_UNSAFE},
87 {"apply" , SYM_APPLY},
88
89 // pattern matching
90 {"?" , SYM_MATCH_ANY},
91
92 // Error symbols with parsable names
93 {"no_match" , SYM_NO_MATCH},
94 {"read_error" , SYM_RERROR},
95 {"type_error" , SYM_TERROR},
96 {"eval_error" , SYM_EERROR},
97 {"out_of_memory" , SYM_MERROR},
98 {"fatal_error" , SYM_FATAL_ERROR},
99 {"out_of_stack" , SYM_STACK_ERROR},
100 {"division_by_zero" , SYM_DIVZERO},
101 {"variable_not_bound" , SYM_NOT_FOUND},
102 {"flash_full" , SYM_ERROR_FLASH_HEAP_FULL},
103
104 // Special symbols with unparsable names
105 {"$barray" , SYM_ARRAY_TYPE},
106 {"$raw_i" , SYM_RAW_I_TYPE},
107 {"$raw_u" , SYM_RAW_U_TYPE},
108 {"$raw_f" , SYM_RAW_F_TYPE},
109 {"$ind_i" , SYM_IND_I_TYPE},
110 {"$ind_u" , SYM_IND_U_TYPE},
111 {"$ind_f" , SYM_IND_F_TYPE},
112 {"$channel" , SYM_CHANNEL_TYPE},
113 {"$recovered" , SYM_RECOVERED},
114 {"$placeholder" , SYM_PLACEHOLDER},
115 {"$custom" , SYM_CUSTOM_TYPE},
116 {"$array" , SYM_LISPARRAY_TYPE},
117 {"$nonsense" , SYM_NONSENSE},
118 {"$dm-array" , SYM_DEFRAG_ARRAY_TYPE},
119 {"$dm" , SYM_DEFRAG_MEM_TYPE},
120
121 // tokenizer symbols with unparsable names
122 {"[openpar]" , SYM_OPENPAR},
123 {"[closepar]" , SYM_CLOSEPAR},
124 {"[backquote]" , SYM_BACKQUOTE},
125 {"[comma]" , SYM_COMMA},
126 {"[commaat]" , SYM_COMMAAT},
127 {"[dot]" , SYM_DOT},
128 {"[done]" , SYM_TOKENIZER_DONE},
129 {"[quote_it]" , SYM_QUOTE_IT},
130 {"[colon]" , SYM_COLON},
131 {"[wait]" , SYM_TOKENIZER_WAIT},
132 {"[openbrack]" , SYM_OPENBRACK},
133 {"[closebrack]" , SYM_CLOSEBRACK},
134 {"[rerror]" , SYM_TOKENIZER_RERROR},
135 {"[appcont]" , SYM_APP_CONT},
136 {"[openarr]" , SYM_OPENARRAY},
137 {"[closearr]" , SYM_CLOSEARRAY},
138
139 // special symbols with parseable names
140 {"type-list" , SYM_TYPE_LIST},
141 {"type-i" , SYM_TYPE_I},
142 {"type-u" , SYM_TYPE_U},
143 {"type-float" , SYM_TYPE_FLOAT},
144 {"type-i32" , SYM_TYPE_I32},
145 {"type-u32" , SYM_TYPE_U32},
146 {"type-double" , SYM_TYPE_DOUBLE},
147 {"type-i64" , SYM_TYPE_I64},
148 {"type-u64" , SYM_TYPE_U64},
149 {"type-array" , SYM_TYPE_ARRAY},
150 {"type-symbol" , SYM_TYPE_SYMBOL},
151 {"type-char" , SYM_TYPE_CHAR},
152 {"type-byte" , SYM_TYPE_BYTE},
153 {"type-channel" , SYM_TYPE_CHANNEL},
154 {"type-lisparray" , SYM_TYPE_LISPARRAY},
155 {"type-dm" , SYM_TYPE_DEFRAG_MEM},
156 {"type-custom" , SYM_TYPE_CUSTOM},
157
158 // Fundamental operations
159 {"+" , SYM_ADD},
160 {"-" , SYM_SUB},
161 {"*" , SYM_MUL},
162 {"/" , SYM_DIV},
163 {"//" , SYM_INT_DIV},
164 {"mod" , SYM_MOD},
165 {"=" , SYM_NUMEQ},
166 {"!=" , SYM_NUM_NOT_EQ},
167 {"<" , SYM_LT},
168 {">" , SYM_GT},
169 {"<=" , SYM_LEQ},
170 {">=" , SYM_GEQ},
171 {"eval" , SYM_EVAL},
172 {"eval-program" , SYM_EVAL_PROGRAM},
173 {"and" , SYM_AND},
174 {"or" , SYM_OR},
175 {"not" , SYM_NOT},
176 {"yield" , SYM_YIELD},
177 {"wait" , SYM_WAIT},
178 {"spawn" , SYM_SPAWN},
179 {"atomic" , SYM_ATOMIC},
180 {"self" , SYM_SELF},
181 {"spawn-trap" , SYM_SPAWN_TRAP},
182 {"set-mailbox-size" , SYM_SET_MAILBOX_SIZE},
183 {"eq" , SYM_EQ},
184 {"not-eq" , SYM_NOT_EQ},
185 {"car" , SYM_CAR},
186 {"cdr" , SYM_CDR},
187 {"cons" , SYM_CONS},
188 {"list" , SYM_LIST},
189 {"append" , SYM_APPEND},
190 {"undefine" , SYM_UNDEFINE},
191 {"bufcreate" , SYM_BYTEARRAY_CREATE},
192 {"type-of" , SYM_TYPE_OF},
193 {"sym2str" , SYM_SYMBOL_TO_STRING},
194 {"str2sym" , SYM_STRING_TO_SYMBOL},
195 {"sym2u" , SYM_SYMBOL_TO_UINT},
196 {"u2sym" , SYM_UINT_TO_SYMBOL},
197 {"setcar" , SYM_SET_CAR},
198 {"setcdr" , SYM_SET_CDR},
199 {"setix" , SYM_SET_IX},
200 {"length" , SYM_LIST_LENGTH},
201 {"range" , SYM_RANGE},
202 {"member" , SYM_MEMBER},
203
204 {"assoc" , SYM_ASSOC}, // lookup an association
205 {"cossa" , SYM_COSSA}, // lookup an association "backwards"
206 {"acons" , SYM_ACONS}, // Add to alist
207 {"setassoc" , SYM_SET_ASSOC}, // Change association
208
209 {"shl" , SYM_SHL},
210 {"shr" , SYM_SHR},
211 {"bitwise-and" , SYM_BITWISE_AND},
212 {"bitwise-or" , SYM_BITWISE_OR},
213 {"bitwise-xor" , SYM_BITWISE_XOR},
214 {"bitwise-not" , SYM_BITWISE_NOT},
215
216 {"custom-destruct", SYM_CUSTOM_DESTRUCT},
217
218 {"to-i" , SYM_TO_I},
219 {"to-i32" , SYM_TO_I32},
220 {"to-u" , SYM_TO_U},
221 {"to-u32" , SYM_TO_U32},
222 {"to-float" , SYM_TO_FLOAT},
223 {"to-i64" , SYM_TO_I64},
224 {"to-u64" , SYM_TO_U64},
225 {"to-double" , SYM_TO_DOUBLE},
226 {"to-byte" , SYM_TO_BYTE},
227
228 {"event-register-handler", SYM_REG_EVENT_HANDLER},
229 {"take" , SYM_TAKE},
230 {"drop" , SYM_DROP},
231 {"mkarray" , SYM_MKARRAY},
232
233 {"dm-create" , SYM_DM_CREATE},
234 {"dm-alloc" , SYM_DM_ALLOC},
235
236 {"list?" , SYM_IS_LIST},
237 {"number?" , SYM_IS_NUMBER},
238 {"string?" , SYM_IS_STRING},
239 {"constant?" , SYM_IS_CONSTANT},
240
241 // fast access in list
242 {"ix" , SYM_IX},
243
244 {"identity" , SYM_IDENTITY},
245 {"array" , SYM_ARRAY},
246
247 // aliases
248 {"first" , SYM_CAR},
249 {"rest" , SYM_CDR},
250 {"fn" , SYM_LAMBDA},
251 {"def" , SYM_DEFINE},
252 {"true" , SYM_TRUE},
253 {"false" , SYM_NIL},
254 {"setvar" , SYM_SETVAR},
255 {"type-f32" , SYM_TYPE_FLOAT},
256 {"type-f64" , SYM_TYPE_DOUBLE},
257 {"array-create" , SYM_BYTEARRAY_CREATE},
258
259 };
260
261 static lbm_uint *symlist = NULL;
262 static lbm_uint next_symbol_id = RUNTIME_SYMBOLS_START;
263 static lbm_uint symbol_table_size_list = 0;
264 static lbm_uint symbol_table_size_list_flash = 0;
265 static lbm_uint symbol_table_size_strings = 0;
266 static lbm_uint symbol_table_size_strings_flash = 0;
267
268 // When rebooting an image...
269 2206 void lbm_symrepr_set_symlist(lbm_uint *ls) {
270 2206 symlist = ls;
271 2206 }
272
273
274 2209 lbm_uint lbm_symrepr_get_next_id(void) {
275 2209 return next_symbol_id;
276 }
277
278 2207 void lbm_symrepr_set_next_id(lbm_uint id) {
279 2207 next_symbol_id = id;
280 2207 }
281
282 44372 bool lbm_symrepr_init(void) {
283 44372 symlist = NULL;
284 44372 next_symbol_id = RUNTIME_SYMBOLS_START;
285 44372 symbol_table_size_list = 0;
286 44372 symbol_table_size_list_flash = 0;
287 44372 symbol_table_size_strings = 0;
288 44372 symbol_table_size_strings_flash = 0;
289 44372 return true;
290 }
291
292 1 void lbm_symrepr_name_iterator(symrepr_name_iterator_fun f) {
293
294 1 lbm_uint *curr = symlist;
295
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
11 while (curr) {
296 10 f((const char *)curr[NAME]);
297 10 curr = (lbm_uint *)curr[NEXT];
298 }
299 1 }
300
301 269665 const char *lookup_symrepr_name_memory(lbm_uint id) {
302
303 269665 lbm_uint *curr = symlist;
304
2/2
✓ Branch 0 taken 3023194 times.
✓ Branch 1 taken 1 times.
3023195 while (curr) {
305
2/2
✓ Branch 0 taken 269664 times.
✓ Branch 1 taken 2753530 times.
3023194 if (id == curr[ID]) {
306 269664 return (const char *)curr[NAME];
307 }
308 2753530 curr = (lbm_uint*)curr[NEXT];
309 }
310 1 return NULL;
311 }
312
313 // Lookup symbol name given a symbol id
314 798184 const char *lbm_get_name_by_symbol(lbm_uint id) {
315 798184 lbm_uint sym_kind = SYMBOL_KIND(id);
316
3/3
✓ Branch 0 taken 512840 times.
✓ Branch 1 taken 15679 times.
✓ Branch 2 taken 269665 times.
798184 switch (sym_kind) {
317 512840 case SYMBOL_KIND_SPECIAL: /* fall through */
318 case SYMBOL_KIND_FUNDAMENTAL:
319 case SYMBOL_KIND_APPFUN:
320
2/2
✓ Branch 0 taken 10182008 times.
✓ Branch 1 taken 14 times.
10182022 for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
321
2/2
✓ Branch 0 taken 512826 times.
✓ Branch 1 taken 9669182 times.
10182008 if (id == special_symbols[i].id) {
322 512826 return (special_symbols[i].name);
323 }
324 }
325 14 return NULL;
326 break;
327 15679 case SYMBOL_KIND_EXTENSION: {
328 15679 lbm_uint ext_id = id - EXTENSION_SYMBOLS_START;
329
1/2
✓ Branch 0 taken 15679 times.
✗ Branch 1 not taken.
15679 if (ext_id < lbm_get_max_extensions()) {
330 15679 return extension_table[ext_id].name;
331 }
332 return NULL;
333 } break;
334 269665 default:
335 269665 return lookup_symrepr_name_memory(id);
336 }
337 }
338
339 5 lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) {
340 5 lbm_uint *curr = symlist;
341
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 3 times.
32 while (curr) {
342 29 char *str = (char*)curr[NAME];
343
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 27 times.
29 if (str_eq(name, str)) {
344 2 return (lbm_uint *)curr;
345 }
346 27 curr = (lbm_uint*)curr[NEXT];
347 }
348 3 return NULL;
349 }
350
351 // Lookup symbol id given symbol name
352 7726437 int lbm_get_symbol_by_name(char *name, lbm_uint* id) {
353
354 // loop through special symbols
355
2/2
✓ Branch 0 taken 1376538397 times.
✓ Branch 1 taken 7048437 times.
1383586834 for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
356
2/2
✓ Branch 0 taken 678000 times.
✓ Branch 1 taken 1375860397 times.
1376538397 if (str_eq(name, (char *)special_symbols[i].name)) {
357 678000 *id = special_symbols[i].id;
358 678000 return 1;
359 }
360 }
361
362 // loop through extensions
363
2/2
✓ Branch 0 taken 1445472718 times.
✓ Branch 1 taken 6952934 times.
1452425652 for (unsigned int i = 0; i < lbm_get_max_extensions(); i ++) {
364
4/4
✓ Branch 0 taken 440418666 times.
✓ Branch 1 taken 1005054052 times.
✓ Branch 2 taken 95503 times.
✓ Branch 3 taken 440323163 times.
1445472718 if (extension_table[i].name && str_eq(name, extension_table[i].name)) {
365 95503 *id = EXTENSION_SYMBOLS_START + i;
366 95503 return 1;
367 }
368 }
369
370 6952934 lbm_uint *curr = symlist;
371
2/2
✓ Branch 0 taken 84548740 times.
✓ Branch 1 taken 5895138 times.
90443878 while (curr) {
372 84548740 char *str = (char*)curr[NAME];
373
2/2
✓ Branch 0 taken 1057796 times.
✓ Branch 1 taken 83490944 times.
84548740 if (str_eq(name, str)) {
374 1057796 *id = curr[ID];
375 1057796 return 1;
376 }
377 83490944 curr = (lbm_uint*)curr[NEXT];
378 }
379 5895138 return 0;
380 }
381
382 extern lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res);
383
384 302642 bool store_symbol_name_flash(char *name, lbm_uint *res) {
385 302642 size_t n = strlen(name) + 1;
386
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 302641 times.
302642 if (n == 1) return 0; // failure if empty symbol
387
388 lbm_uint alloc_size;
389
2/2
✓ Branch 0 taken 34002 times.
✓ Branch 1 taken 268639 times.
302641 if (n % sizeof(lbm_uint) == 0) {
390 34002 alloc_size = n/(sizeof(lbm_uint));
391 } else {
392 268639 alloc_size = (n/(sizeof(lbm_uint))) + 1;
393 }
394
395 302641 lbm_uint symbol_addr = 0;
396 302641 lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr);
397
2/4
✓ Branch 0 taken 302641 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 302641 times.
302641 if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) {
398 return false;
399 }
400 302641 symbol_table_size_strings_flash += alloc_size;
401 302641 *res = symbol_addr;
402 302641 return true;
403 }
404
405 // Symbol table
406 // non-const name copied into symbol-table-entry:
407 // Entry
408 // |
409 // [name-ptr | symbol-id | next-ptr | name n-bytes]
410 // | /
411 // ------------points here -----
412 //
413 // const name referenced by symbol-table-entry:
414 // Entry
415 // |
416 // [name-ptr | symbol-id | next-ptr]
417 // |
418 // [name n-bytes]
419 //
420
421 302642 int lbm_add_symbol_base(char *name, lbm_uint *id) {
422 lbm_uint symbol_name_storage;
423
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 302641 times.
302642 if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0;
424 302641 lbm_uint *new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist);
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 302641 times.
302641 if (!new_symlist) {
426 return 0;
427 }
428 302641 symlist = new_symlist;
429 302641 *id = next_symbol_id ++;
430 302641 return 1;
431 }
432
433 216016 int lbm_add_symbol(char *name, lbm_uint* id) {
434 lbm_uint sym_id;
435
2/2
✓ Branch 0 taken 89491 times.
✓ Branch 1 taken 126525 times.
216016 if (!lbm_get_symbol_by_name(name, &sym_id)) {
436 89491 return lbm_add_symbol_base(name, id);
437 } else {
438 126525 *id = sym_id;
439 126525 return 1;
440 }
441 return 0;
442 }
443
444 // on Linux, win, etc a const string may not be at
445 // the same address between runs.
446 890932 int lbm_add_symbol_const_base(char *name, lbm_uint* id, bool link) {
447 890932 lbm_uint symbol_name_storage = (lbm_uint)name;
448 lbm_uint *new_symlist;
449
2/2
✓ Branch 0 taken 890917 times.
✓ Branch 1 taken 15 times.
890932 if (link) {
450 890917 new_symlist = lbm_image_add_and_link_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist, id);
451 } else {
452 15 new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist);
453 }
454
1/2
✓ Branch 0 taken 890932 times.
✗ Branch 1 not taken.
890932 if (new_symlist) {
455 890932 symlist = new_symlist;
456 890932 *id = next_symbol_id ++;
457 890932 return 1;
458 }
459 return 0;
460 }
461
462 941907 int lbm_add_symbol_const(char *name, lbm_uint* id) {
463 lbm_uint sym_id;
464
2/2
✓ Branch 0 taken 890916 times.
✓ Branch 1 taken 50991 times.
941907 if (!lbm_get_symbol_by_name(name, &sym_id)) {
465 890916 return lbm_add_symbol_const_base(name, id, true);
466 } else {
467 50991 *id = sym_id;
468 50991 return 1;
469 }
470 return 0;
471 }
472
473 118 int lbm_str_to_symbol(char *name, lbm_uint *sym_id) {
474
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 59 times.
118 if (lbm_get_symbol_by_name(name, sym_id))
475 59 return 1;
476
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 else if (lbm_add_symbol(name, sym_id))
477 59 return 1;
478 return 0;
479 }
480
481 58 lbm_uint lbm_get_symbol_table_size(void) {
482 58 return (symbol_table_size_list +symbol_table_size_strings);
483 }
484
485 58 lbm_uint lbm_get_symbol_table_size_flash(void) {
486 58 return (symbol_table_size_list_flash +
487 58 symbol_table_size_strings_flash) * sizeof(lbm_uint);
488 }
489
490 58 lbm_uint lbm_get_symbol_table_size_names(void) {
491 58 return symbol_table_size_strings; // Bytes already
492 }
493
494 58 lbm_uint lbm_get_symbol_table_size_names_flash(void) {
495 58 return symbol_table_size_strings_flash * sizeof(lbm_uint);
496 }
497
498 1 bool lbm_symbol_in_flash(char *str) {
499 1 return !lbm_memory_ptr_inside((lbm_uint*)str);
500 }
501
502 2 bool lbm_symbol_list_entry_in_flash(char *str) {
503 2 lbm_uint *entry = lbm_get_symbol_list_entry_by_name(str);
504
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 return (entry == NULL || !lbm_memory_ptr_inside(entry));
505 }
506