GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/symrepr.c Lines: 128 159 80.5 %
Date: 2025-01-19 11:10:47 Branches: 47 73 64.4 %

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
  {"call-cc-unsafe", SYM_CALL_CC_UNSAFE},
85
86
  // pattern matching
87
  {"?"          , SYM_MATCH_ANY},
88
89
  // Error symbols with parsable names
90
  {"no_match"           , SYM_NO_MATCH},
91
  {"read_error"         , SYM_RERROR},
92
  {"type_error"         , SYM_TERROR},
93
  {"eval_error"         , SYM_EERROR},
94
  {"out_of_memory"      , SYM_MERROR},
95
  {"fatal_error"        , SYM_FATAL_ERROR},
96
  {"out_of_stack"       , SYM_STACK_ERROR},
97
  {"division_by_zero"   , SYM_DIVZERO},
98
  {"variable_not_bound" , SYM_NOT_FOUND},
99
  {"flash_full"         , SYM_ERROR_FLASH_HEAP_FULL},
100
101
  // Special symbols with unparsable names
102
  {"$barray"         , SYM_ARRAY_TYPE},
103
  {"$raw_i"          , SYM_RAW_I_TYPE},
104
  {"$raw_u"          , SYM_RAW_U_TYPE},
105
  {"$raw_f"          , SYM_RAW_F_TYPE},
106
  {"$ind_i"          , SYM_IND_I_TYPE},
107
  {"$ind_u"          , SYM_IND_U_TYPE},
108
  {"$ind_f"          , SYM_IND_F_TYPE},
109
  {"$channel"        , SYM_CHANNEL_TYPE},
110
  {"$recovered"      , SYM_RECOVERED},
111
  {"$placeholder"    , SYM_PLACEHOLDER},
112
  {"$custom"         , SYM_CUSTOM_TYPE},
113
  {"$array"          , SYM_LISPARRAY_TYPE},
114
  {"$nonsense"       , SYM_NONSENSE},
115
  {"$dm-array"       , SYM_DEFRAG_ARRAY_TYPE},
116
  {"$dm"             , SYM_DEFRAG_MEM_TYPE},
117
118
  // tokenizer symbols with unparsable names
119
  {"[openpar]"        , SYM_OPENPAR},
120
  {"[closepar]"       , SYM_CLOSEPAR},
121
  {"[backquote]"      , SYM_BACKQUOTE},
122
  {"[comma]"          , SYM_COMMA},
123
  {"[commaat]"        , SYM_COMMAAT},
124
  {"[dot]"            , SYM_DOT},
125
  {"[done]"           , SYM_TOKENIZER_DONE},
126
  {"[quote_it]"       , SYM_QUOTE_IT},
127
  {"[colon]"          , SYM_COLON},
128
  {"[wait]"           , SYM_TOKENIZER_WAIT},
129
  {"[openbrack]"      , SYM_OPENBRACK},
130
  {"[closebrack]"     , SYM_CLOSEBRACK},
131
  {"[rerror]"         , SYM_TOKENIZER_RERROR},
132
  {"[appcont]"        , SYM_APP_CONT},
133
134
  // special symbols with parseable names
135
  {"type-list"        , SYM_TYPE_LIST},
136
  {"type-i"           , SYM_TYPE_I},
137
  {"type-u"           , SYM_TYPE_U},
138
  {"type-float"       , SYM_TYPE_FLOAT},
139
  {"type-i32"         , SYM_TYPE_I32},
140
  {"type-u32"         , SYM_TYPE_U32},
141
  {"type-double"      , SYM_TYPE_DOUBLE},
142
  {"type-i64"         , SYM_TYPE_I64},
143
  {"type-u64"         , SYM_TYPE_U64},
144
  {"type-array"       , SYM_TYPE_ARRAY},
145
  {"type-symbol"      , SYM_TYPE_SYMBOL},
146
  {"type-char"        , SYM_TYPE_CHAR},
147
  {"type-byte"        , SYM_TYPE_BYTE},
148
  {"type-channel"     , SYM_TYPE_CHANNEL},
149
  {"type-lisparray"   , SYM_TYPE_LISPARRAY},
150
  {"type-dm"          , SYM_TYPE_DEFRAG_MEM},
151
  {"type-custom"      , SYM_TYPE_CUSTOM},
152
153
  // Fundamental operations
154
  {"+"                , SYM_ADD},
155
  {"-"                , SYM_SUB},
156
  {"*"                , SYM_MUL},
157
  {"/"                , SYM_DIV},
158
  {"//"               , SYM_INT_DIV},
159
  {"mod"              , SYM_MOD},
160
  {"="                , SYM_NUMEQ},
161
  {"!="               , SYM_NUM_NOT_EQ},
162
  {"<"                , SYM_LT},
163
  {">"                , SYM_GT},
164
  {"<="               , SYM_LEQ},
165
  {">="               , SYM_GEQ},
166
  {"eval"             , SYM_EVAL},
167
  {"eval-program"     , SYM_EVAL_PROGRAM},
168
  {"and"              , SYM_AND},
169
  {"or"               , SYM_OR},
170
  {"not"              , SYM_NOT},
171
  {"yield"            , SYM_YIELD},
172
  {"wait"             , SYM_WAIT},
173
  {"spawn"            , SYM_SPAWN},
174
  {"atomic"           , SYM_ATOMIC},
175
  {"self"             , SYM_SELF},
176
  {"spawn-trap"       , SYM_SPAWN_TRAP},
177
  {"set-mailbox-size" , SYM_SET_MAILBOX_SIZE},
178
  {"eq"               , SYM_EQ},
179
  {"not-eq"           , SYM_NOT_EQ},
180
  {"car"              , SYM_CAR},
181
  {"cdr"              , SYM_CDR},
182
  {"cons"             , SYM_CONS},
183
  {"list"             , SYM_LIST},
184
  {"append"           , SYM_APPEND},
185
  {"undefine"         , SYM_UNDEFINE},
186
  {"bufcreate"        , SYM_BYTEARRAY_CREATE},
187
  {"type-of"          , SYM_TYPE_OF},
188
  {"sym2str"          , SYM_SYMBOL_TO_STRING},
189
  {"str2sym"          , SYM_STRING_TO_SYMBOL},
190
  {"sym2u"            , SYM_SYMBOL_TO_UINT},
191
  {"u2sym"            , SYM_UINT_TO_SYMBOL},
192
  {"setcar"           , SYM_SET_CAR},
193
  {"setcdr"           , SYM_SET_CDR},
194
  {"setix"            , SYM_SET_IX},
195
  {"length"           , SYM_LIST_LENGTH},
196
  {"range"            , SYM_RANGE},
197
198
  {"assoc"          , SYM_ASSOC}, // lookup an association
199
  {"cossa"          , SYM_COSSA}, // lookup an association "backwards"
200
  {"acons"          , SYM_ACONS}, // Add to alist
201
  {"setassoc"       , SYM_SET_ASSOC}, // Change association
202
203
  {"shl"            , SYM_SHL},
204
  {"shr"            , SYM_SHR},
205
  {"bitwise-and"    , SYM_BITWISE_AND},
206
  {"bitwise-or"     , SYM_BITWISE_OR},
207
  {"bitwise-xor"    , SYM_BITWISE_XOR},
208
  {"bitwise-not"    , SYM_BITWISE_NOT},
209
210
  {"custom-destruct", SYM_CUSTOM_DESTRUCT},
211
212
  {"to-i"           , SYM_TO_I},
213
  {"to-i32"         , SYM_TO_I32},
214
  {"to-u"           , SYM_TO_U},
215
  {"to-u32"         , SYM_TO_U32},
216
  {"to-float"       , SYM_TO_FLOAT},
217
  {"to-i64"         , SYM_TO_I64},
218
  {"to-u64"         , SYM_TO_U64},
219
  {"to-double"      , SYM_TO_DOUBLE},
220
  {"to-byte"        , SYM_TO_BYTE},
221
222
  {"event-register-handler", SYM_REG_EVENT_HANDLER},
223
  {"take"           , SYM_TAKE},
224
  {"drop"           , SYM_DROP},
225
  {"mkarray"        , SYM_MKARRAY},
226
  {"array-to-list"  , SYM_ARRAY_TO_LIST},
227
  {"list-to-array"  , SYM_LIST_TO_ARRAY},
228
229
  {"dm-create"      , SYM_DM_CREATE},
230
  {"dm-alloc"       , SYM_DM_ALLOC},
231
232
  {"list?"          , SYM_IS_LIST},
233
  {"number?"        , SYM_IS_NUMBER},
234
235
  // fast access in list
236
  {"ix"             , SYM_IX},
237
238
  // aliases
239
  {"first"          , SYM_CAR},
240
  {"rest"           , SYM_CDR},
241
  {"fn"             , SYM_LAMBDA},
242
  {"def"            , SYM_DEFINE},
243
  {"true"           , SYM_TRUE},
244
  {"false"          , SYM_NIL},
245
  {"setvar"         , SYM_SETVAR},
246
  {"type-f32"       , SYM_TYPE_FLOAT},
247
  {"type-f64"       , SYM_TYPE_DOUBLE},
248
  {"array-create"   , SYM_BYTEARRAY_CREATE},
249
  {"identity"       , SYM_IDENTITY},
250
};
251
252
static lbm_uint *symlist = NULL;
253
static lbm_uint next_symbol_id = RUNTIME_SYMBOLS_START;
254
static lbm_uint symbol_table_size_list = 0;
255
static lbm_uint symbol_table_size_list_flash = 0;
256
static lbm_uint symbol_table_size_strings = 0;
257
static lbm_uint symbol_table_size_strings_flash = 0;
258
259
lbm_value symbol_x = ENC_SYM_NIL;
260
lbm_value symbol_y = ENC_SYM_NIL;
261
262
21588
int lbm_symrepr_init(void) {
263
21588
  symlist = NULL;
264
21588
  next_symbol_id = RUNTIME_SYMBOLS_START;
265
21588
  symbol_table_size_list = 0;
266
21588
  symbol_table_size_list_flash = 0;
267
21588
  symbol_table_size_strings = 0;
268
21588
  symbol_table_size_strings_flash = 0;
269
270
21588
  lbm_uint x = 0;
271
21588
  lbm_uint y = 0;
272
21588
  lbm_add_symbol("x", &x);
273
21588
  lbm_add_symbol("y", &y);
274
21588
  symbol_x = lbm_enc_sym(x);
275
21588
  symbol_y = lbm_enc_sym(y);
276
21588
  return 1;
277
}
278
279
void lbm_symrepr_name_iterator(symrepr_name_iterator_fun f) {
280
281
  lbm_uint *curr = symlist;
282
  while (curr) {
283
    f((const char *)curr[NAME]);
284
    curr = (lbm_uint *)curr[NEXT];
285
  }
286
}
287
288
131528
const char *lookup_symrepr_name_memory(lbm_uint id) {
289
290
131528
  lbm_uint *curr = symlist;
291
1481788
  while (curr) {
292
1481788
    if (id == curr[ID]) {
293
131528
      return (const char *)curr[NAME];
294
    }
295
1350260
    curr = (lbm_uint*)curr[NEXT];
296
  }
297
  return NULL;
298
}
299
300
// Lookup symbol name given a symbol id
301
390605
const char *lbm_get_name_by_symbol(lbm_uint id) {
302
390605
  lbm_uint sym_kind = SYMBOL_KIND(id);
303
390605
  switch (sym_kind) {
304
251285
  case SYMBOL_KIND_SPECIAL:  /* fall through */
305
  case SYMBOL_KIND_FUNDAMENTAL:
306
  case SYMBOL_KIND_APPFUN:
307
4690369
    for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
308
4690355
      if (id == special_symbols[i].id) {
309
251271
        return (special_symbols[i].name);
310
      }
311
    }
312
14
    return NULL;
313
    break;
314
7792
  case SYMBOL_KIND_EXTENSION: {
315
7792
    lbm_uint ext_id = id - EXTENSION_SYMBOLS_START;
316
7792
    if (ext_id < lbm_get_max_extensions()) {
317
7792
      return extension_table[ext_id].name;
318
    }
319
    return NULL;
320
  } break;
321
131528
  default:
322
131528
    return lookup_symrepr_name_memory(id);
323
  }
324
}
325
326
lbm_uint *lbm_get_symbol_list_entry_by_name(char *name) {
327
  lbm_uint *curr = symlist;
328
  while (curr) {
329
    char *str = (char*)curr[NAME];
330
    if (str_eq(name, str)) {
331
      return (lbm_uint *)curr;
332
    }
333
    curr = (lbm_uint*)curr[NEXT];
334
  }
335
  return NULL;
336
}
337
338
// Lookup symbol id given symbol name
339
3601392
int lbm_get_symbol_by_name(char *name, lbm_uint* id) {
340
341
  // loop through special symbols
342
627635936
  for (unsigned int i = 0; i < NUM_SPECIAL_SYMBOLS; i ++) {
343
624352488
    if (str_eq(name, (char *)special_symbols[i].name)) {
344
317944
      *id = special_symbols[i].id;
345
317944
      return 1;
346
    }
347
   }
348
349
  // loop through extensions
350
645628424
  for (unsigned int i = 0; i < lbm_get_max_extensions(); i ++) {
351

642387900
    if (extension_table[i].name && str_eq(name, extension_table[i].name)) {
352
42924
      *id = EXTENSION_SYMBOLS_START + i;
353
42924
      return 1;
354
    }
355
  }
356
357
3240524
  lbm_uint *curr = symlist;
358
41360244
  while (curr) {
359
38605478
    char *str = (char*)curr[NAME];
360
38605478
    if (str_eq(name, str)) {
361
485758
      *id = curr[ID];
362
485758
      return 1;
363
    }
364
38119720
    curr = (lbm_uint*)curr[NEXT];
365
  }
366
2754766
  return 0;
367
}
368
369
extern lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res);
370
371
372
70
static bool store_symbol_name_flash(char *name, lbm_uint *res) {
373
70
  size_t n = strlen(name) + 1;
374
70
  if (n == 1) return 0; // failure if empty symbol
375
376
  lbm_uint alloc_size;
377
70
  if (n % sizeof(lbm_uint) == 0) {
378
    alloc_size = n/(sizeof(lbm_uint));
379
  } else {
380
70
    alloc_size = (n/(sizeof(lbm_uint))) + 1;
381
  }
382
383
70
  lbm_uint symbol_addr = 0;
384
70
  lbm_flash_status s = lbm_write_const_array_padded((uint8_t*)name, n, &symbol_addr);
385

70
  if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) {
386
    return false;
387
  }
388
70
  symbol_table_size_strings_flash += alloc_size;
389
70
  *res = symbol_addr;
390
70
  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
142488
static bool add_symbol_to_symtab(char* name, lbm_uint id) {
409
142488
  bool r = false;
410
142488
  size_t n = strlen(name) + 1;
411

142488
  if (n > 1 && n <= 257) {
412
142488
    size_t alloc_size = n + (3 * sizeof(lbm_uint));
413
142488
    char *storage = lbm_malloc(alloc_size);
414
142488
    if (storage) {
415
142478
      memcpy(storage + (3 * sizeof(lbm_uint)), name, n);
416
142478
      lbm_uint *m = (lbm_uint*)storage;
417
418
142478
      symbol_table_size_list += 3 * sizeof(lbm_uint); // Bytes
419
142478
      symbol_table_size_strings += n; // Bytes
420
142478
      m[NAME] = (lbm_uint)&m[3];
421
142478
      m[NEXT] = (lbm_uint) symlist;
422
142478
      symlist = m;
423
142478
      m[ID] =id;
424
142478
      r = true;
425
    }
426
  }
427
142488
  return r;
428
}
429
430
70
static bool add_symbol_to_symtab_flash(lbm_uint name, lbm_uint id) {
431
  lbm_uint entry[3];
432
70
  entry[NAME] = name;
433
70
  entry[NEXT] = (lbm_uint) symlist;
434
70
  entry[ID]   = id;
435
70
  lbm_uint entry_addr = 0;
436
70
  if (lbm_write_const_raw(entry,3, &entry_addr) == LBM_FLASH_WRITE_OK) {
437
70
    symlist = (lbm_uint*)entry_addr;
438
70
    symbol_table_size_list_flash += 3;
439
70
    return true;
440
  }
441
  return false;
442
}
443
444
142558
int lbm_add_symbol_base(char *name, lbm_uint *id, bool flash) {
445
  lbm_uint symbol_name_storage;
446
142558
  if (flash) {
447
70
    if (!store_symbol_name_flash(name, &symbol_name_storage)) return 0;
448
70
    if (!add_symbol_to_symtab_flash(symbol_name_storage, next_symbol_id)) return 0;
449
  } else {
450
142488
    if (!add_symbol_to_symtab(name, next_symbol_id)) {
451
10
      return 0;
452
    }
453
  }
454
142548
  *id = next_symbol_id ++;
455
142548
  return 1;
456
}
457
458
106726
int lbm_add_symbol(char *name, lbm_uint* id) {
459
  lbm_uint sym_id;
460
106726
  if (!lbm_get_symbol_by_name(name, &sym_id)) {
461
43204
    return lbm_add_symbol_base(name, id, false);
462
  } else {
463
63522
    *id = sym_id;
464
63522
    return 1;
465
  }
466
  return 0;
467
}
468
469
int lbm_add_symbol_flash(char *name, lbm_uint* id) {
470
  lbm_uint sym_id;
471
  if (!lbm_get_symbol_by_name(name, &sym_id)) {
472
    return lbm_add_symbol_base(name, id, true);
473
  } else {
474
    *id = sym_id;
475
    return 1;
476
  }
477
  return 0;
478
}
479
480
431760
int lbm_add_symbol_const_base(char *name, lbm_uint* id) {
481
431760
  lbm_uint *m = lbm_memory_allocate(3);
482
431760
  if (m == NULL) return 0;
483
431760
  symbol_table_size_list += 3;
484
431760
  m[NAME] = (lbm_uint) name;
485
431760
  m[NEXT] = (lbm_uint) symlist;
486
431760
  symlist = m;
487
431760
  m[ID] = next_symbol_id;
488
431760
  *id = next_symbol_id ++;
489
431760
  return 1;
490
}
491
492
431760
int lbm_add_symbol_const(char *name, lbm_uint* id) {
493
  lbm_uint sym_id;
494
431760
  if (!lbm_get_symbol_by_name(name, &sym_id)) {
495
431760
    return lbm_add_symbol_const_base(name, id);
496
  } else {
497
    *id = sym_id;
498
    return 1;
499
  }
500
  return 0;
501
}
502
503
56
int lbm_str_to_symbol(char *name, lbm_uint *sym_id) {
504
56
  if (lbm_get_symbol_by_name(name, sym_id))
505
28
    return 1;
506
28
  else if (lbm_add_symbol(name, sym_id))
507
28
    return 1;
508
  return 0;
509
}
510
511
28
lbm_uint lbm_get_symbol_table_size(void) {
512
28
  return (symbol_table_size_list +symbol_table_size_strings);
513
}
514
515
28
lbm_uint lbm_get_symbol_table_size_flash(void) {
516
28
  return (symbol_table_size_list_flash +
517
28
          symbol_table_size_strings_flash) * sizeof(lbm_uint);
518
}
519
520
28
lbm_uint lbm_get_symbol_table_size_names(void) {
521
28
  return symbol_table_size_strings; // Bytes already
522
}
523
524
28
lbm_uint lbm_get_symbol_table_size_names_flash(void) {
525
28
  return symbol_table_size_strings_flash * sizeof(lbm_uint);
526
}
527
528
bool lbm_symbol_in_flash(char *str) {
529
  return !lbm_memory_ptr_inside((lbm_uint*)str);
530
}
531
532
bool lbm_symbol_list_entry_in_flash(char *str) {
533
  lbm_uint *entry = lbm_get_symbol_list_entry_by_name(str);
534
  return (entry == NULL || !lbm_memory_ptr_inside(entry));
535
}