GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/symrepr.c
Date: 2024-08-06 17:32:21
Exec Total Coverage
Lines: 88 161 54.7%
Functions: 9 21 42.9%
Branches: 34 75 45.3%

Line Branch Exec Source
1 /*
2 Copyright 2018, 2021, 2022, 2024 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 <stdint.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <inttypes.h>
23
24
25 #include <lbm_memory.h>
26 #include <heap.h>
27 #include "symrepr.h"
28 #include "extensions.h"
29 #include "lbm_utils.h"
30
31 #define NUM_SPECIAL_SYMBOLS (sizeof(special_symbols) / sizeof(special_sym))
32 #define NAME 0
33 #define ID 1
34 #define NEXT 2
35
36 typedef struct {
37 const char *name;
38 const lbm_uint id;
39 } special_sym;
40
41 special_sym const special_symbols[] = {
42 {"nil" , SYM_NIL},
43 {"quote" , SYM_QUOTE},
44 {"t" , SYM_TRUE},
45 {"if" , SYM_IF},
46 {"cond" , SYM_COND},
47 {"lambda" , SYM_LAMBDA},
48 {"closure" , SYM_CLOSURE},
49 {"let" , SYM_LET},
50 {"define" , SYM_DEFINE},
51 {"progn" , SYM_PROGN},
52 {"read" , SYM_READ},
53 {"read-program" , SYM_READ_PROGRAM},
54 {"read-eval-program", SYM_READ_AND_EVAL_PROGRAM},
55 {"match" , SYM_MATCH},
56 {"_" , SYM_DONTCARE},
57 {"send" , SYM_SEND},
58 {"recv" , SYM_RECEIVE},
59 {"recv-to" , SYM_RECEIVE_TIMEOUT},
60 {"macro" , SYM_MACRO},
61 {"call-cc" , SYM_CALLCC},
62 {"continuation" , SYM_CONT},
63 {"var" , SYM_PROGN_VAR},
64 {"timeout" , SYM_TIMEOUT},
65
66 {"set" , SYM_SETVAR},
67 {"setq" , SYM_SETQ},
68 {"move-to-flash", SYM_MOVE_TO_FLASH},
69 {"exit-ok" , SYM_EXIT_OK},
70 {"exit-error" , SYM_EXIT_ERROR},
71 {"map" , SYM_MAP},
72 {"reverse" , SYM_REVERSE},
73 {"flatten" , SYM_FLATTEN},
74 {"unflatten" , SYM_UNFLATTEN},
75 {"kill" , SYM_KILL},
76 {"sleep" , SYM_SLEEP},
77 {"merge" , SYM_MERGE},
78 {"sort" , SYM_SORT},
79 {"gc" , SYM_PERFORM_GC},
80 {"loop" , SYM_LOOP},
81 {"trap" , SYM_TRAP},
82 {"rest-args" , SYM_REST_ARGS},
83 {"rotate" , SYM_ROTATE},
84
85 // pattern matching
86 {"?" , SYM_MATCH_ANY},
87
88 // Error symbols with parsable names
89 {"no_match" , SYM_NO_MATCH},
90 {"read_error" , SYM_RERROR},
91 {"type_error" , SYM_TERROR},
92 {"eval_error" , SYM_EERROR},
93 {"out_of_memory" , SYM_MERROR},
94 {"fatal_error" , SYM_FATAL_ERROR},
95 {"out_of_stack" , SYM_STACK_ERROR},
96 {"division_by_zero" , SYM_DIVZERO},
97 {"variable_not_bound" , SYM_NOT_FOUND},
98 {"flash_full" , SYM_ERROR_FLASH_HEAP_FULL},
99
100 // Special symbols with unparsable names
101 {"$barray" , SYM_ARRAY_TYPE},
102 {"$raw_i" , SYM_RAW_I_TYPE},
103 {"$raw_u" , SYM_RAW_U_TYPE},
104 {"$raw_f" , SYM_RAW_F_TYPE},
105 {"$ind_i" , SYM_IND_I_TYPE},
106 {"$ind_u" , SYM_IND_U_TYPE},
107 {"$ind_f" , SYM_IND_F_TYPE},
108 {"$channel" , SYM_CHANNEL_TYPE},
109 {"$recovered" , SYM_RECOVERED},
110 {"$custom" , SYM_CUSTOM_TYPE},
111 {"$array" , SYM_LISPARRAY_TYPE},
112 {"$nonsense" , SYM_NONSENSE},
113
114 // tokenizer symbols with unparsable names
115 {"[openpar]" , SYM_OPENPAR},
116 {"[closepar]" , SYM_CLOSEPAR},
117 {"[backquote]" , SYM_BACKQUOTE},
118 {"[comma]" , SYM_COMMA},
119 {"[commaat]" , SYM_COMMAAT},
120 {"[dot]" , SYM_DOT},
121 {"[done]" , SYM_TOKENIZER_DONE},
122 {"[quote_it]" , SYM_QUOTE_IT},
123 {"[colon]" , SYM_COLON},
124 {"[wait]" , SYM_TOKENIZER_WAIT},
125 {"[openbrack]" , SYM_OPENBRACK},
126 {"[closebrack]" , SYM_CLOSEBRACK},
127 {"[rerror]" , SYM_TOKENIZER_RERROR},
128 {"[appcont]" , SYM_APP_CONT},
129
130 // special symbols with parseable names
131 {"type-list" , SYM_TYPE_LIST},
132 {"type-i" , SYM_TYPE_I},
133 {"type-u" , SYM_TYPE_U},
134 {"type-float" , SYM_TYPE_FLOAT},
135 {"type-i32" , SYM_TYPE_I32},
136 {"type-u32" , SYM_TYPE_U32},
137 {"type-double" , SYM_TYPE_DOUBLE},
138 {"type-i64" , SYM_TYPE_I64},
139 {"type-u64" , SYM_TYPE_U64},
140 {"type-array" , SYM_TYPE_ARRAY},
141 {"type-symbol" , SYM_TYPE_SYMBOL},
142 {"type-char" , SYM_TYPE_CHAR},
143 {"type-byte" , SYM_TYPE_BYTE},
144 {"type-channel" , SYM_TYPE_CHANNEL},
145 {"type-lisparray" , SYM_TYPE_LISPARRAY},
146
147 // Fundamental operations
148 {"+" , SYM_ADD},
149 {"-" , SYM_SUB},
150 {"*" , SYM_MUL},
151 {"/" , SYM_DIV},
152 {"mod" , SYM_MOD},
153 {"=" , SYM_NUMEQ},
154 {"!=" , SYM_NUM_NOT_EQ},
155 {"<" , SYM_LT},
156 {">" , SYM_GT},
157 {"<=" , SYM_LEQ},
158 {">=" , SYM_GEQ},
159 {"eval" , SYM_EVAL},
160 {"eval-program" , SYM_EVAL_PROGRAM},
161 {"and" , SYM_AND},
162 {"or" , SYM_OR},
163 {"not" , SYM_NOT},
164 {"yield" , SYM_YIELD},
165 {"wait" , SYM_WAIT},
166 {"spawn" , SYM_SPAWN},
167 {"atomic" , SYM_ATOMIC},
168 {"self" , SYM_SELF},
169 {"spawn-trap" , SYM_SPAWN_TRAP},
170 {"set-mailbox-size" , SYM_SET_MAILBOX_SIZE},
171 {"eq" , SYM_EQ},
172 {"not-eq" , SYM_NOT_EQ},
173 {"car" , SYM_CAR},
174 {"cdr" , SYM_CDR},
175 {"cons" , SYM_CONS},
176 {"list" , SYM_LIST},
177 {"append" , SYM_APPEND},
178 {"undefine" , SYM_UNDEFINE},
179 {"bufcreate" , SYM_BYTEARRAY_CREATE},
180 {"type-of" , SYM_TYPE_OF},
181 {"sym2str" , SYM_SYMBOL_TO_STRING},
182 {"str2sym" , SYM_STRING_TO_SYMBOL},
183 {"sym2u" , SYM_SYMBOL_TO_UINT},
184 {"u2sym" , SYM_UINT_TO_SYMBOL},
185 {"setcar" , SYM_SET_CAR},
186 {"setcdr" , SYM_SET_CDR},
187 {"setix" , SYM_SET_IX},
188 {"length" , SYM_LIST_LENGTH},
189 {"range" , SYM_RANGE},
190
191 {"assoc" , SYM_ASSOC}, // lookup an association
192 {"cossa" , SYM_COSSA}, // lookup an association "backwards"
193 {"acons" , SYM_ACONS}, // Add to alist
194 {"setassoc" , SYM_SET_ASSOC}, // Change association
195
196 {"shl" , SYM_SHL},
197 {"shr" , SYM_SHR},
198 {"bitwise-and" , SYM_BITWISE_AND},
199 {"bitwise-or" , SYM_BITWISE_OR},
200 {"bitwise-xor" , SYM_BITWISE_XOR},
201 {"bitwise-not" , SYM_BITWISE_NOT},
202
203 {"custom-destruct", SYM_CUSTOM_DESTRUCT},
204
205 {"to-i" , SYM_TO_I},
206 {"to-i32" , SYM_TO_I32},
207 {"to-u" , SYM_TO_U},
208 {"to-u32" , SYM_TO_U32},
209 {"to-float" , SYM_TO_FLOAT},
210 {"to-i64" , SYM_TO_I64},
211 {"to-u64" , SYM_TO_U64},
212 {"to-double" , SYM_TO_DOUBLE},
213 {"to-byte" , SYM_TO_BYTE},
214
215 {"event-register-handler", SYM_REG_EVENT_HANDLER},
216 {"take" , SYM_TAKE},
217 {"drop" , SYM_DROP},
218 {"mkarray" , SYM_MKARRAY},
219 {"array-to-list" , SYM_ARRAY_TO_LIST},
220 {"list-to-array" , SYM_LIST_TO_ARRAY},
221
222 // fast access in list
223 {"ix" , SYM_IX},
224
225 // aliases
226 {"first" , SYM_CAR},
227 {"rest" , SYM_CDR},
228 {"fn" , SYM_LAMBDA},
229 {"def" , SYM_DEFINE},
230 {"true" , SYM_TRUE},
231 {"false" , SYM_NIL},
232 {"setvar" , SYM_SETVAR},
233 {"type-f32" , SYM_TYPE_FLOAT},
234 {"type-f64" , SYM_TYPE_DOUBLE},
235 {"array-create" , SYM_BYTEARRAY_CREATE},
236 };
237
238 static lbm_uint *symlist = NULL;
239 static lbm_uint next_symbol_id = RUNTIME_SYMBOLS_START;
240 static lbm_uint symbol_table_size_list = 0;
241 static lbm_uint symbol_table_size_list_flash = 0;
242 static lbm_uint symbol_table_size_strings = 0;
243 static lbm_uint symbol_table_size_strings_flash = 0;
244
245 lbm_value symbol_x = ENC_SYM_NIL;
246 lbm_value symbol_y = ENC_SYM_NIL;
247
248 17444 int lbm_symrepr_init(void) {
249 17444 symlist = NULL;
250 17444 next_symbol_id = RUNTIME_SYMBOLS_START;
251 17444 symbol_table_size_list = 0;
252 17444 symbol_table_size_list_flash = 0;
253 17444 symbol_table_size_strings = 0;
254 17444 symbol_table_size_strings_flash = 0;
255
256 17444 lbm_uint x = 0;
257 17444 lbm_uint y = 0;
258 17444 lbm_add_symbol("x", &x);
259 17444 lbm_add_symbol("y", &y);
260 17444 symbol_x = lbm_enc_sym(x);
261 17444 symbol_y = lbm_enc_sym(y);
262 17444 return 1;
263 }
264
265 void lbm_symrepr_name_iterator(symrepr_name_iterator_fun f) {
266
267 lbm_uint *curr = symlist;
268 while (curr) {
269 f((const char *)curr[NAME]);
270 curr = (lbm_uint *)curr[NEXT];
271 }
272 }
273
274 4720 const char *lookup_symrepr_name_memory(lbm_uint id) {
275
276 4720 lbm_uint *curr = symlist;
277
1/2
✓ Branch 0 taken 22110 times.
✗ Branch 1 not taken.
22110 while (curr) {
278
2/2
✓ Branch 0 taken 4720 times.
✓ Branch 1 taken 17390 times.
22110 if (id == curr[ID]) {
279 4720 return (const char *)curr[NAME];
280 }
281 17390 curr = (lbm_uint*)curr[NEXT];
282 }
283 return NULL;
284 }
285
286 // Lookup symbol name given a symbol id
287 40947 const char *lbm_get_name_by_symbol(lbm_uint id) {
288 40947 lbm_uint sym_kind = SYMBOL_KIND(id);
289
3/3
✓ Branch 0 taken 36219 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 4720 times.
40947 switch (sym_kind) {
290 36219 case SYMBOL_KIND_SPECIAL: /* fall through */
291 case SYMBOL_KIND_FUNDAMENTAL:
292 case SYMBOL_KIND_APPFUN:
293
1/2
✓ Branch 0 taken 126435 times.
✗ Branch 1 not taken.
126435 for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
294
2/2
✓ Branch 0 taken 36219 times.
✓ Branch 1 taken 90216 times.
126435 if (id == special_symbols[i].id) {
295 36219 return (special_symbols[i].name);
296 }
297 }
298 return NULL;
299 break;
300 8 case SYMBOL_KIND_EXTENSION: {
301 8 lbm_uint ext_id = id - EXTENSION_SYMBOLS_START;
302
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (ext_id < lbm_get_max_extensions()) {
303 8 return extension_table[ext_id].name;
304 }
305 return NULL;
306 } break;
307 4720 default:
308 4720 return lookup_symrepr_name_memory(id);
309 }
310 }
311
312 lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) {
313 lbm_uint *curr = symlist;
314 while (curr) {
315 char *str = (char*)curr[NAME];
316 if (str_eq(name, str)) {
317 return (lbm_uint *)curr;
318 }
319 curr = (lbm_uint*)curr[NEXT];
320 }
321 return NULL;
322 }
323
324 // Lookup symbol id given symbol name
325 2505258 int lbm_get_symbol_by_name(char *name, lbm_uint* id) {
326
327 // loop through special symbols
328
2/2
✓ Branch 0 taken 412356336 times.
✓ Branch 1 taken 2326254 times.
414682590 for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
329
2/2
✓ Branch 1 taken 179004 times.
✓ Branch 2 taken 412177332 times.
412356336 if (str_eq(name, (char *)special_symbols[i].name)) {
330 179004 *id = special_symbols[i].id;
331 179004 return 1;
332 }
333 }
334
335 // loop through extensions
336
2/2
✓ Branch 1 taken 228575900 times.
✓ Branch 2 taken 2299766 times.
230875666 for (unsigned int i = 0; i < lbm_get_max_extensions(); i ++) {
337
4/4
✓ Branch 0 taken 121615060 times.
✓ Branch 1 taken 106960840 times.
✓ Branch 3 taken 26488 times.
✓ Branch 4 taken 121588572 times.
228575900 if (extension_table[i].name && str_eq(name, extension_table[i].name)) {
338 26488 *id = EXTENSION_SYMBOLS_START + i;
339 26488 return 1;
340 }
341 }
342
343 2299766 lbm_uint *curr = symlist;
344
2/2
✓ Branch 0 taken 26753076 times.
✓ Branch 1 taken 2183202 times.
28936278 while (curr) {
345 26753076 char *str = (char*)curr[NAME];
346
2/2
✓ Branch 1 taken 116564 times.
✓ Branch 2 taken 26636512 times.
26753076 if (str_eq(name, str)) {
347 116564 *id = curr[ID];
348 116564 return 1;
349 }
350 26636512 curr = (lbm_uint*)curr[NEXT];
351 }
352 2183202 return 0;
353 }
354
355 extern lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res);
356
357
358 static bool store_symbol_name_flash(char *name, lbm_uint *res) {
359 size_t n = strlen(name) + 1;
360 if (n == 1) return 0; // failure if empty symbol
361
362 lbm_uint alloc_size;
363 if (n % sizeof(lbm_uint) == 0) {
364 alloc_size = n/(sizeof(lbm_uint));
365 } else {
366 alloc_size = (n/(sizeof(lbm_uint))) + 1;
367 }
368
369 lbm_uint symbol_addr = 0;
370 lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr);
371 if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) {
372 return false;
373 }
374 symbol_table_size_strings_flash += alloc_size;
375 *res = symbol_addr;
376 return true;
377 }
378
379 107324 static bool add_symbol_to_symtab(char* name, lbm_uint id) {
380 107324 size_t n = strlen(name) + 1;
381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107324 times.
107324 if (n == 1) return 0; // failure if empty symbol
382
383 lbm_uint alloc_size;
384
2/2
✓ Branch 0 taken 16016 times.
✓ Branch 1 taken 91308 times.
107324 if (n % sizeof(lbm_uint) == 0) {
385 16016 alloc_size = n/(sizeof(lbm_uint));
386 } else {
387 91308 alloc_size = (n/(sizeof(lbm_uint))) + 1;
388 }
389
390 107324 lbm_uint *storage = lbm_memory_allocate(alloc_size + 3);
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107324 times.
107324 if (storage == NULL) return false;
392 107324 strncpy(((char*)storage) + (3 * sizeof(lbm_uint)), name, n);
393 107324 lbm_uint *m = storage;
394
395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107324 times.
107324 if (m == NULL) return false;
396
397 107324 symbol_table_size_list += 3;
398 107324 m[NAME] = (lbm_uint)&storage[3];
399 107324 m[NEXT] = (lbm_uint) symlist;
400 107324 symlist = m;
401 107324 m[ID] =id;
402 107324 return true;
403 }
404
405 static bool add_symbol_to_symtab_flash(lbm_uint name, lbm_uint id) {
406 lbm_uint entry[3];
407 entry[NAME] = name;
408 entry[NEXT] = (lbm_uint) symlist;
409 entry[ID] = id;
410 lbm_uint entry_addr = 0;
411 if (lbm_write_const_raw(entry,3, &entry_addr) == LBM_FLASH_WRITE_OK) {
412 symlist = (lbm_uint*)entry_addr;
413 symbol_table_size_list_flash += 3;
414 return true;
415 }
416 return false;
417 }
418
419 107324 int lbm_add_symbol_base(char *name, lbm_uint *id, bool flash) {
420 lbm_uint symbol_name_storage;
421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107324 times.
107324 if (flash) {
422 if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0;
423 if (!add_symbol_to_symtab_flash(symbol_name_storage, next_symbol_id)) return 0;
424 } else {
425
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 107324 times.
107324 if (!add_symbol_to_symtab(name, next_symbol_id)) {
426 return 0;
427 }
428 }
429 107324 *id = next_symbol_id ++;
430 107324 return 1;
431 }
432
433 34888 int lbm_add_symbol(char *name, lbm_uint* id) {
434 lbm_uint sym_id;
435
1/2
✓ Branch 1 taken 34888 times.
✗ Branch 2 not taken.
34888 if (!lbm_get_symbol_by_name(name, &sym_id)) {
436 34888 return lbm_add_symbol_base(name, id, false);
437 } else {
438 *id = sym_id;
439 return 1;
440 }
441 return 0;
442 }
443
444 int lbm_add_symbol_flash(char *name, lbm_uint* id) {
445 lbm_uint sym_id;
446 if (!lbm_get_symbol_by_name(name, &sym_id)) {
447 return lbm_add_symbol_base(name, id, true);
448 } else {
449 *id = sym_id;
450 return 1;
451 }
452 return 0;
453 }
454
455 331436 int lbm_add_symbol_const_base(char *name, lbm_uint* id) {
456 331436 lbm_uint *m = lbm_memory_allocate(3);
457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331436 times.
331436 if (m == NULL) return 0;
458 331436 symbol_table_size_list += 3;
459 331436 m[NAME] = (lbm_uint) name;
460 331436 m[NEXT] = (lbm_uint) symlist;
461 331436 symlist = m;
462 331436 m[ID] = next_symbol_id;
463 331436 *id = next_symbol_id ++;
464 331436 return 1;
465 }
466
467 331436 int lbm_add_symbol_const(char *name, lbm_uint* id) {
468 lbm_uint sym_id;
469
1/2
✓ Branch 1 taken 331436 times.
✗ Branch 2 not taken.
331436 if (!lbm_get_symbol_by_name(name, &sym_id)) {
470 331436 return lbm_add_symbol_const_base(name, id);
471 } else {
472 *id = sym_id;
473 return 1;
474 }
475 return 0;
476 }
477
478 int lbm_str_to_symbol(char *name, lbm_uint *sym_id) {
479 if (lbm_get_symbol_by_name(name, sym_id))
480 return 1;
481 else if (lbm_add_symbol(name, sym_id))
482 return 1;
483 return 0;
484 }
485
486 lbm_uint lbm_get_symbol_table_size(void) {
487 return (symbol_table_size_list +
488 symbol_table_size_strings) * sizeof(lbm_uint);
489 }
490
491 lbm_uint lbm_get_symbol_table_size_flash(void) {
492 return (symbol_table_size_list_flash +
493 symbol_table_size_strings_flash) * sizeof(lbm_uint);
494 }
495
496 lbm_uint lbm_get_symbol_table_size_names(void) {
497 return symbol_table_size_strings * sizeof(lbm_uint);
498 }
499
500 lbm_uint lbm_get_symbol_table_size_names_flash(void) {
501 return symbol_table_size_strings_flash * sizeof(lbm_uint);
502 }
503
504 bool lbm_symbol_in_flash(char *str) {
505 return !lbm_memory_ptr_inside((lbm_uint*)str);
506 }
507
508 bool lbm_symbol_list_entry_in_flash(char *str) {
509 lbm_uint *entry = lbm_get_symbol_list_entry_by_name(str);
510 return (entry == NULL || !lbm_memory_ptr_inside(entry));
511 }
512