GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/symrepr.c Lines: 127 159 79.9 %
Date: 2024-12-26 17:59:19 Branches: 45 73 61.6 %

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

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

70
  if (s != LBM_FLASH_WRITE_OK || symbol_addr == 0) {
385
    return false;
386
  }
387
70
  symbol_table_size_strings_flash += alloc_size;
388
70
  *res = symbol_addr;
389
70
  return true;
390
}
391
392
// Symbol table
393
// non-const name copied into symbol-table-entry:
394
// Entry
395
//   |
396
//   [name-ptr | symbol-id | next-ptr | name n-bytes]
397
//       |                             /
398
//        ------------points here -----
399
//
400
// const name referenced by symbol-table-entry:
401
// Entry
402
//   |
403
//   [name-ptr | symbol-id | next-ptr]
404
//       |
405
//        [name n-bytes]
406
//
407
143458
static bool add_symbol_to_symtab(char* name, lbm_uint id) {
408
143458
  bool r = false;
409
143458
  size_t n = strlen(name) + 1;
410

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