GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/symrepr.c Lines: 97 124 78.2 %
Date: 2025-04-09 11:39:30 Branches: 42 63 66.7 %

Line Branch Exec Source
1
/*
2
    Copyright 2018, 2021, 2022, 2024, 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 <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
#include "lbm_image.h"
31
32
#define NUM_SPECIAL_SYMBOLS (sizeof(special_symbols) / sizeof(special_sym))
33
#define NAME   0
34
#define ID     1
35
#define NEXT   2
36
37
typedef struct {
38
  const char *name;
39
  const lbm_uint id;
40
} special_sym;
41
42
special_sym const special_symbols[] =  {
43
  {"nil"        , SYM_NIL},
44
  {"quote"      , SYM_QUOTE},
45
  {"t"          , SYM_TRUE},
46
  {"if"         , SYM_IF},
47
  {"cond"       , SYM_COND},
48
  {"lambda"     , SYM_LAMBDA},
49
  {"closure"    , SYM_CLOSURE},
50
  {"let"        , SYM_LET},
51
  {"define"     , SYM_DEFINE},
52
  {"progn"      , SYM_PROGN},
53
  {"read"       , SYM_READ},
54
  {"read-program" , SYM_READ_PROGRAM},
55
  {"read-eval-program", SYM_READ_AND_EVAL_PROGRAM},
56
  {"match"        , SYM_MATCH},
57
  {"_"            , SYM_DONTCARE},
58
  {"send"         , SYM_SEND},
59
  {"recv"         , SYM_RECEIVE},
60
  {"recv-to"      , SYM_RECEIVE_TIMEOUT},
61
  {"macro"        , SYM_MACRO},
62
  {"call-cc"      , SYM_CALLCC},
63
  {"continuation" , SYM_CONT},
64
  {"var"          , SYM_PROGN_VAR},
65
  {"timeout"      , SYM_TIMEOUT},
66
67
  {"set"          , SYM_SETVAR},
68
  {"setq"         , SYM_SETQ},
69
  {"move-to-flash", SYM_MOVE_TO_FLASH},
70
  {"exit-ok"      , SYM_EXIT_OK},
71
  {"exit-error"   , SYM_EXIT_ERROR},
72
  {"map"          , SYM_MAP},
73
  {"reverse"      , SYM_REVERSE},
74
  {"flatten"      , SYM_FLATTEN},
75
  {"unflatten"    , SYM_UNFLATTEN},
76
  {"kill"         , SYM_KILL},
77
  {"sleep"        , SYM_SLEEP},
78
  {"merge"        , SYM_MERGE},
79
  {"sort"         , SYM_SORT},
80
  {"gc"           , SYM_PERFORM_GC},
81
  {"loop"         , SYM_LOOP},
82
  {"trap"         , SYM_TRAP},
83
  {"rest-args"    , SYM_REST_ARGS},
84
  {"rotate"       , SYM_ROTATE},
85
  {"call-cc-unsafe", SYM_CALL_CC_UNSAFE},
86
87
  // pattern matching
88
  {"?"          , SYM_MATCH_ANY},
89
90
  // Error symbols with parsable names
91
  {"no_match"           , SYM_NO_MATCH},
92
  {"read_error"         , SYM_RERROR},
93
  {"type_error"         , SYM_TERROR},
94
  {"eval_error"         , SYM_EERROR},
95
  {"out_of_memory"      , SYM_MERROR},
96
  {"fatal_error"        , SYM_FATAL_ERROR},
97
  {"out_of_stack"       , SYM_STACK_ERROR},
98
  {"division_by_zero"   , SYM_DIVZERO},
99
  {"variable_not_bound" , SYM_NOT_FOUND},
100
  {"flash_full"         , SYM_ERROR_FLASH_HEAP_FULL},
101
102
  // Special symbols with unparsable names
103
  {"$barray"         , SYM_ARRAY_TYPE},
104
  {"$raw_i"          , SYM_RAW_I_TYPE},
105
  {"$raw_u"          , SYM_RAW_U_TYPE},
106
  {"$raw_f"          , SYM_RAW_F_TYPE},
107
  {"$ind_i"          , SYM_IND_I_TYPE},
108
  {"$ind_u"          , SYM_IND_U_TYPE},
109
  {"$ind_f"          , SYM_IND_F_TYPE},
110
  {"$channel"        , SYM_CHANNEL_TYPE},
111
  {"$recovered"      , SYM_RECOVERED},
112
  {"$placeholder"    , SYM_PLACEHOLDER},
113
  {"$custom"         , SYM_CUSTOM_TYPE},
114
  {"$array"          , SYM_LISPARRAY_TYPE},
115
  {"$nonsense"       , SYM_NONSENSE},
116
  {"$dm-array"       , SYM_DEFRAG_ARRAY_TYPE},
117
  {"$dm"             , SYM_DEFRAG_MEM_TYPE},
118
119
  // tokenizer symbols with unparsable names
120
  {"[openpar]"        , SYM_OPENPAR},
121
  {"[closepar]"       , SYM_CLOSEPAR},
122
  {"[backquote]"      , SYM_BACKQUOTE},
123
  {"[comma]"          , SYM_COMMA},
124
  {"[commaat]"        , SYM_COMMAAT},
125
  {"[dot]"            , SYM_DOT},
126
  {"[done]"           , SYM_TOKENIZER_DONE},
127
  {"[quote_it]"       , SYM_QUOTE_IT},
128
  {"[colon]"          , SYM_COLON},
129
  {"[wait]"           , SYM_TOKENIZER_WAIT},
130
  {"[openbrack]"      , SYM_OPENBRACK},
131
  {"[closebrack]"     , SYM_CLOSEBRACK},
132
  {"[rerror]"         , SYM_TOKENIZER_RERROR},
133
  {"[appcont]"        , SYM_APP_CONT},
134
  {"[openarr]"        , SYM_OPENARRAY},
135
  {"[closearr]"       , SYM_CLOSEARRAY},
136
137
  // special symbols with parseable names
138
  {"type-list"        , SYM_TYPE_LIST},
139
  {"type-i"           , SYM_TYPE_I},
140
  {"type-u"           , SYM_TYPE_U},
141
  {"type-float"       , SYM_TYPE_FLOAT},
142
  {"type-i32"         , SYM_TYPE_I32},
143
  {"type-u32"         , SYM_TYPE_U32},
144
  {"type-double"      , SYM_TYPE_DOUBLE},
145
  {"type-i64"         , SYM_TYPE_I64},
146
  {"type-u64"         , SYM_TYPE_U64},
147
  {"type-array"       , SYM_TYPE_ARRAY},
148
  {"type-symbol"      , SYM_TYPE_SYMBOL},
149
  {"type-char"        , SYM_TYPE_CHAR},
150
  {"type-byte"        , SYM_TYPE_BYTE},
151
  {"type-channel"     , SYM_TYPE_CHANNEL},
152
  {"type-lisparray"   , SYM_TYPE_LISPARRAY},
153
  {"type-dm"          , SYM_TYPE_DEFRAG_MEM},
154
  {"type-custom"      , SYM_TYPE_CUSTOM},
155
156
  // Fundamental operations
157
  {"+"                , SYM_ADD},
158
  {"-"                , SYM_SUB},
159
  {"*"                , SYM_MUL},
160
  {"/"                , SYM_DIV},
161
  {"//"               , SYM_INT_DIV},
162
  {"mod"              , SYM_MOD},
163
  {"="                , SYM_NUMEQ},
164
  {"!="               , SYM_NUM_NOT_EQ},
165
  {"<"                , SYM_LT},
166
  {">"                , SYM_GT},
167
  {"<="               , SYM_LEQ},
168
  {">="               , SYM_GEQ},
169
  {"eval"             , SYM_EVAL},
170
  {"eval-program"     , SYM_EVAL_PROGRAM},
171
  {"and"              , SYM_AND},
172
  {"or"               , SYM_OR},
173
  {"not"              , SYM_NOT},
174
  {"yield"            , SYM_YIELD},
175
  {"wait"             , SYM_WAIT},
176
  {"spawn"            , SYM_SPAWN},
177
  {"atomic"           , SYM_ATOMIC},
178
  {"self"             , SYM_SELF},
179
  {"spawn-trap"       , SYM_SPAWN_TRAP},
180
  {"set-mailbox-size" , SYM_SET_MAILBOX_SIZE},
181
  {"eq"               , SYM_EQ},
182
  {"not-eq"           , SYM_NOT_EQ},
183
  {"car"              , SYM_CAR},
184
  {"cdr"              , SYM_CDR},
185
  {"cons"             , SYM_CONS},
186
  {"list"             , SYM_LIST},
187
  {"append"           , SYM_APPEND},
188
  {"undefine"         , SYM_UNDEFINE},
189
  {"bufcreate"        , SYM_BYTEARRAY_CREATE},
190
  {"type-of"          , SYM_TYPE_OF},
191
  {"sym2str"          , SYM_SYMBOL_TO_STRING},
192
  {"str2sym"          , SYM_STRING_TO_SYMBOL},
193
  {"sym2u"            , SYM_SYMBOL_TO_UINT},
194
  {"u2sym"            , SYM_UINT_TO_SYMBOL},
195
  {"setcar"           , SYM_SET_CAR},
196
  {"setcdr"           , SYM_SET_CDR},
197
  {"setix"            , SYM_SET_IX},
198
  {"length"           , SYM_LIST_LENGTH},
199
  {"range"            , SYM_RANGE},
200
201
  {"assoc"          , SYM_ASSOC}, // lookup an association
202
  {"cossa"          , SYM_COSSA}, // lookup an association "backwards"
203
  {"acons"          , SYM_ACONS}, // Add to alist
204
  {"setassoc"       , SYM_SET_ASSOC}, // Change association
205
206
  {"shl"            , SYM_SHL},
207
  {"shr"            , SYM_SHR},
208
  {"bitwise-and"    , SYM_BITWISE_AND},
209
  {"bitwise-or"     , SYM_BITWISE_OR},
210
  {"bitwise-xor"    , SYM_BITWISE_XOR},
211
  {"bitwise-not"    , SYM_BITWISE_NOT},
212
213
  {"custom-destruct", SYM_CUSTOM_DESTRUCT},
214
215
  {"to-i"           , SYM_TO_I},
216
  {"to-i32"         , SYM_TO_I32},
217
  {"to-u"           , SYM_TO_U},
218
  {"to-u32"         , SYM_TO_U32},
219
  {"to-float"       , SYM_TO_FLOAT},
220
  {"to-i64"         , SYM_TO_I64},
221
  {"to-u64"         , SYM_TO_U64},
222
  {"to-double"      , SYM_TO_DOUBLE},
223
  {"to-byte"        , SYM_TO_BYTE},
224
225
  {"event-register-handler", SYM_REG_EVENT_HANDLER},
226
  {"take"           , SYM_TAKE},
227
  {"drop"           , SYM_DROP},
228
  {"mkarray"        , SYM_MKARRAY},
229
230
  {"dm-create"      , SYM_DM_CREATE},
231
  {"dm-alloc"       , SYM_DM_ALLOC},
232
233
  {"list?"          , SYM_IS_LIST},
234
  {"number?"        , SYM_IS_NUMBER},
235
  {"string?"        , SYM_IS_STRING},
236
  {"constant?"      , SYM_IS_CONSTANT},
237
238
  // fast access in list
239
  {"ix"             , SYM_IX},
240
241
  {"identity"       , SYM_IDENTITY},
242
  {"array"          , SYM_ARRAY},
243
244
  // aliases
245
  {"first"          , SYM_CAR},
246
  {"rest"           , SYM_CDR},
247
  {"fn"             , SYM_LAMBDA},
248
  {"def"            , SYM_DEFINE},
249
  {"true"           , SYM_TRUE},
250
  {"false"          , SYM_NIL},
251
  {"setvar"         , SYM_SETVAR},
252
  {"type-f32"       , SYM_TYPE_FLOAT},
253
  {"type-f64"       , SYM_TYPE_DOUBLE},
254
  {"array-create"   , SYM_BYTEARRAY_CREATE},
255
256
};
257
258
static lbm_uint *symlist = NULL;
259
static lbm_uint next_symbol_id = RUNTIME_SYMBOLS_START;
260
static lbm_uint symbol_table_size_list = 0;
261
static lbm_uint symbol_table_size_list_flash = 0;
262
static lbm_uint symbol_table_size_strings = 0;
263
static lbm_uint symbol_table_size_strings_flash = 0;
264
265
// When rebooting an image...
266
void lbm_symrepr_set_symlist(lbm_uint *ls) {
267
  symlist = ls;
268
}
269
270
21924
int lbm_symrepr_init(void) {
271
21924
  symlist = NULL;
272
21924
  next_symbol_id = RUNTIME_SYMBOLS_START;
273
21924
  symbol_table_size_list = 0;
274
21924
  symbol_table_size_list_flash = 0;
275
21924
  symbol_table_size_strings = 0;
276
21924
  symbol_table_size_strings_flash = 0;
277
21924
  return 1;
278
}
279
280
void lbm_symrepr_name_iterator(symrepr_name_iterator_fun f) {
281
282
  lbm_uint *curr = symlist;
283
  while (curr) {
284
    f((const char *)curr[NAME]);
285
    curr = (lbm_uint *)curr[NEXT];
286
  }
287
}
288
289
135172
const char *lookup_symrepr_name_memory(lbm_uint id) {
290
291
135172
  lbm_uint *curr = symlist;
292
1512372
  while (curr) {
293
1512372
    if (id == curr[ID]) {
294
135172
      return (const char *)curr[NAME];
295
    }
296
1377200
    curr = (lbm_uint*)curr[NEXT];
297
  }
298
  return NULL;
299
}
300
301
// Lookup symbol name given a symbol id
302
397910
const char *lbm_get_name_by_symbol(lbm_uint id) {
303
397910
  lbm_uint sym_kind = SYMBOL_KIND(id);
304
397910
  switch (sym_kind) {
305
254786
  case SYMBOL_KIND_SPECIAL:  /* fall through */
306
  case SYMBOL_KIND_FUNDAMENTAL:
307
  case SYMBOL_KIND_APPFUN:
308
4954772
    for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
309
4954758
      if (id == special_symbols[i].id) {
310
254772
        return (special_symbols[i].name);
311
      }
312
    }
313
14
    return NULL;
314
    break;
315
7952
  case SYMBOL_KIND_EXTENSION: {
316
7952
    lbm_uint ext_id = id - EXTENSION_SYMBOLS_START;
317
7952
    if (ext_id < lbm_get_max_extensions()) {
318
7952
      return extension_table[ext_id].name;
319
    }
320
    return NULL;
321
  } break;
322
135172
  default:
323
135172
    return lookup_symrepr_name_memory(id);
324
  }
325
}
326
327
lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) {
328
  lbm_uint *curr = symlist;
329
  while (curr) {
330
    char *str = (char*)curr[NAME];
331
    if (str_eq(name, str)) {
332
      return (lbm_uint *)curr;
333
    }
334
    curr = (lbm_uint*)curr[NEXT];
335
  }
336
  return NULL;
337
}
338
339
// Lookup symbol id given symbol name
340
3793742
int lbm_get_symbol_by_name(char *name, lbm_uint* id) {
341
342
  // loop through special symbols
343
672192128
  for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
344
668731290
    if (str_eq(name, (char *)special_symbols[i].name)) {
345
332904
      *id = special_symbols[i].id;
346
332904
      return 1;
347
    }
348
   }
349
350
  // loop through extensions
351
689854956
  for (unsigned int i = 0; i < lbm_get_max_extensions(); i ++) {
352

686438354
    if (extension_table[i].name && str_eq(name, extension_table[i].name)) {
353
44236
      *id = EXTENSION_SYMBOLS_START + i;
354
44236
      return 1;
355
    }
356
  }
357
358
3416602
  lbm_uint *curr = symlist;
359
43933646
  while (curr) {
360
41042026
    char *str = (char*)curr[NAME];
361
41042026
    if (str_eq(name, str)) {
362
524982
      *id = curr[ID];
363
524982
      return 1;
364
    }
365
40517044
    curr = (lbm_uint*)curr[NEXT];
366
  }
367
2891620
  return 0;
368
}
369
370
extern lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res);
371
372
589530
bool store_symbol_name_flash(char *name, lbm_uint *res) {
373
589530
  size_t n = strlen(name) + 1;
374
589530
  if (n == 1) return 0; // failure if empty symbol
375
376
  lbm_uint alloc_size;
377
589530
  if (n % sizeof(lbm_uint) == 0) {
378
153606
    alloc_size = n/(sizeof(lbm_uint));
379
  } else {
380
435924
    alloc_size = (n/(sizeof(lbm_uint))) + 1;
381
  }
382
383
589530
  lbm_uint symbol_addr = 0;
384
589530
  lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr);
385

589530
  if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) {
386
    return false;
387
  }
388
589530
  symbol_table_size_strings_flash += alloc_size;
389
589530
  *res = symbol_addr;
390
589530
  return true;
391
}
392
393
// Symbol table
394
// non-const name copied into symbol-table-entry:
395
// Entry
396
//   |
397
//   [name-ptr | symbol-id | next-ptr | name n-bytes]
398
//       |                             /
399
//        ------------points here -----
400
//
401
// const name referenced by symbol-table-entry:
402
// Entry
403
//   |
404
//   [name-ptr | symbol-id | next-ptr]
405
//       |
406
//        [name n-bytes]
407
//
408
409
151050
int lbm_add_symbol_base(char *name, lbm_uint *id) {
410
  lbm_uint symbol_name_storage;
411
151050
  if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0;
412
151050
  lbm_uint *new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist);
413
151050
  if (!new_symlist) {
414
    return 0;
415
  }
416
151050
  symlist = new_symlist;
417
151050
  *id = next_symbol_id ++;
418
151050
  return 1;
419
}
420
421
106664
int lbm_add_symbol(char *name, lbm_uint* id) {
422
  lbm_uint sym_id;
423
106664
  if (!lbm_get_symbol_by_name(name, &sym_id)) {
424
43876
    return lbm_add_symbol_base(name, id);
425
  } else {
426
62788
    *id = sym_id;
427
62788
    return 1;
428
  }
429
  return 0;
430
}
431
432
// on Linux, win, etc a const string may not be at
433
// the same address between runs.
434
438480
int lbm_add_symbol_const_base(char *name, lbm_uint* id, bool link) {
435
438480
  lbm_uint symbol_name_storage = (lbm_uint)name;
436
#ifdef __PIC__
437
438480
  if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0;
438
#endif
439
  lbm_uint *new_symlist;
440
438480
  if (link) {
441
438480
    new_symlist = lbm_image_add_and_link_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist, id);
442
  } else {
443
    new_symlist = lbm_image_add_symbol((char*)symbol_name_storage, next_symbol_id, (lbm_uint)symlist);
444
  }
445
438480
  if (new_symlist) {
446
438480
    symlist = new_symlist;
447
438480
    *id = next_symbol_id ++;
448
438480
    return 1;
449
  }
450
  return 0;
451
}
452
453
460404
int lbm_add_symbol_const(char *name, lbm_uint* id) {
454
  lbm_uint sym_id;
455
460404
  if (!lbm_get_symbol_by_name(name, &sym_id)) {
456
438480
    return lbm_add_symbol_const_base(name, id, true);
457
  } else {
458
21924
    *id = sym_id;
459
21924
    return 1;
460
  }
461
  return 0;
462
}
463
464
56
int lbm_str_to_symbol(char *name, lbm_uint *sym_id) {
465
56
  if (lbm_get_symbol_by_name(name, sym_id))
466
28
    return 1;
467
28
  else if (lbm_add_symbol(name, sym_id))
468
28
    return 1;
469
  return 0;
470
}
471
472
28
lbm_uint lbm_get_symbol_table_size(void) {
473
28
  return (symbol_table_size_list +symbol_table_size_strings);
474
}
475
476
28
lbm_uint lbm_get_symbol_table_size_flash(void) {
477
28
  return (symbol_table_size_list_flash +
478
28
          symbol_table_size_strings_flash) * sizeof(lbm_uint);
479
}
480
481
28
lbm_uint lbm_get_symbol_table_size_names(void) {
482
28
  return symbol_table_size_strings; // Bytes already
483
}
484
485
28
lbm_uint lbm_get_symbol_table_size_names_flash(void) {
486
28
  return symbol_table_size_strings_flash * sizeof(lbm_uint);
487
}
488
489
bool lbm_symbol_in_flash(char *str) {
490
  return !lbm_memory_ptr_inside((lbm_uint*)str);
491
}
492
493
bool lbm_symbol_list_entry_in_flash(char *str) {
494
  lbm_uint *entry = lbm_get_symbol_list_entry_by_name(str);
495
  return (entry == NULL || !lbm_memory_ptr_inside(entry));
496
}