GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/lbm_flat_value.c Lines: 420 487 86.2 %
Date: 2024-12-05 14:36:58 Branches: 186 311 59.8 %

Line Branch Exec Source
1
/*
2
    Copyright 2023, 2024 Joel Svensson    svenssonjoel@yahoo.se
3
              2023       Benjamin Vedder
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 <lbm_flat_value.h>
20
#include <eval_cps.h>
21
#include <stack.h>
22
23
#include <setjmp.h>
24
25
// ------------------------------------------------------------
26
// Access to GC from eval_cps
27
int lbm_perform_gc(void);
28
29
30
// ------------------------------------------------------------
31
// Flatteners
32
33
42189
bool lbm_start_flatten(lbm_flat_value_t *v, size_t buffer_size) {
34
42189
  bool res = false;
35
42189
  uint8_t *data = lbm_malloc_reserve(buffer_size);
36
42189
  if (data) {
37
42189
    v->buf = data;
38
42189
    v->buf_size = buffer_size;
39
42189
    v->buf_pos = 0;
40
42189
    res = true;
41
  }
42
42189
  return res;
43
}
44
45
7651
bool lbm_finish_flatten(lbm_flat_value_t *v) {
46
  lbm_uint size_words;
47
7651
  if (v->buf_pos % sizeof(lbm_uint) == 0) {
48
    size_words = v->buf_pos / sizeof(lbm_uint);
49
  } else {
50
7651
    size_words = (v->buf_pos / sizeof(lbm_uint)) + 1;
51
  }
52
7651
  if (v->buf_size  <= size_words * sizeof(lbm_uint)) return true;
53
7623
  v->buf_size = size_words * sizeof(lbm_uint);
54
7623
  return (lbm_memory_shrink((lbm_uint*)v->buf, size_words) >= 0);
55
}
56
57
422513
static bool write_byte(lbm_flat_value_t *v, uint8_t b) {
58
422513
  bool res = false;
59
422513
  if (v->buf_size >= v->buf_pos + 1) {
60
422513
    v->buf[v->buf_pos++] = b;
61
422513
    res = true;
62
  }
63
422513
  return res;
64
}
65
66
181776
static bool write_bytes(lbm_flat_value_t *v, uint8_t *data,lbm_uint num_bytes) {
67
181776
  bool res = false;
68
181776
  if (v->buf_size >= v->buf_pos + num_bytes) {
69
181776
    memcpy(v->buf + v->buf_pos, data, num_bytes);
70
181776
    v->buf_pos += num_bytes;
71
181776
    res = true;
72
  }
73
181776
  return res;
74
}
75
76
238161
static bool write_word(lbm_flat_value_t *v, uint32_t w) {
77
238161
  bool res = false;
78
238161
  if (v->buf_size >= v->buf_pos + 4) {
79
238161
    v->buf[v->buf_pos++] = (uint8_t)(w >> 24);
80
238161
    v->buf[v->buf_pos++] = (uint8_t)(w >> 16);
81
238161
    v->buf[v->buf_pos++] = (uint8_t)(w >> 8);
82
238161
    v->buf[v->buf_pos++] = (uint8_t)w;
83
238161
    res = true;
84
  }
85
238161
  return res;
86
}
87
88
84
static bool write_dword(lbm_flat_value_t *v, uint64_t w) {
89
84
  bool res = false;
90
84
  if (v->buf_size >= v->buf_pos + 8) {
91
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 56);
92
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 48);
93
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 40);
94
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 32);
95
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 24);
96
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 16);
97
84
    v->buf[v->buf_pos++] = (uint8_t)(w >> 8);
98
84
    v->buf[v->buf_pos++] = (uint8_t)w;
99
84
    res = true;
100
  }
101
84
  return res;
102
}
103
104
319452
bool f_cons(lbm_flat_value_t *v) {
105
319452
  bool res = false;
106
319452
  if (v->buf_size >= v->buf_pos + 1) {
107
319452
    v->buf[v->buf_pos++] = S_CONS;
108
319452
    res = true;
109
  }
110
319452
  return res;
111
}
112
113
84
bool f_lisp_array(lbm_flat_value_t *v, uint32_t size) {
114
  // arrays are smaller than 2^32 elements long
115
84
  bool res = true;
116

84
  res = res && write_byte(v, S_LBM_LISP_ARRAY);
117

84
  res = res && write_word(v, size); // number of elements.
118
84
  return res;
119
}
120
121
5891
bool f_sym(lbm_flat_value_t *v, lbm_uint sym_id) {
122
5891
  bool res = true;
123

5891
  res = res && write_byte(v,S_SYM_VALUE);
124
  #ifndef LBM64
125

5891
  res = res && write_word(v,sym_id);
126
  #else
127
  res = res && write_dword(v,sym_id);
128
  #endif
129
5891
  return res;
130
}
131
132
63028
bool f_sym_string(lbm_flat_value_t *v, char *str) {
133
63028
  bool res = false;
134
63028
  if (str) {
135
63028
    lbm_uint sym_bytes = strlen(str) + 1;
136

126056
    if (write_byte(v, S_SYM_STRING) &&
137
63028
	write_bytes(v, (uint8_t*)str, sym_bytes)) {
138
63028
      res = true;
139
    }
140
  }
141
63028
  return res;
142
}
143
144
// Potentially a difference between 32/64 bit version.
145
// strlen returns size_t which is different on 32/64 bit platforms.
146
62972
int f_sym_string_bytes(lbm_value sym) {
147
62972
  int res = FLATTEN_VALUE_ERROR_FATAL;
148
62972
  if (lbm_is_symbol(sym)) {
149
62972
    lbm_uint s = lbm_dec_sym(sym);
150
62972
    char *sym_str = (char*)lbm_get_name_by_symbol(s);
151
62972
    if (sym_str) {
152
62972
      lbm_uint sym_bytes = strlen(sym_str) + 1;
153
62972
      res = (int)sym_bytes;
154
    }
155
  }
156
62972
  return res;
157
}
158
159
45374
bool f_i(lbm_flat_value_t *v, lbm_int i) {
160
45374
  bool res = true;
161
#ifndef LBM64
162

45374
  res = res && write_byte(v,S_I28_VALUE);
163

45374
  res = res && write_word(v,(uint32_t)i);
164
#else
165
  res = res && write_byte(v,S_I56_VALUE);
166
  res = res && write_dword(v, (uint64_t)i);
167
#endif
168
45374
  return res;
169
}
170
171
28
bool f_u(lbm_flat_value_t *v, lbm_uint u) {
172
28
  bool res = true;
173
#ifndef LBM64
174

28
  res = res && write_byte(v,S_U28_VALUE);
175

28
  res = res && write_word(v,(uint32_t)u);
176
#else
177
  res = res && write_byte(v,S_U56_VALUE);
178
  res = res && write_dword(v,(uint64_t)u);
179
#endif
180
28
  return res;
181
}
182
183
60620
bool f_b(lbm_flat_value_t *v, uint8_t b) {
184
60620
  bool res = true;
185

60620
  res = res && write_byte(v,S_BYTE_VALUE);
186

60620
  res = res && write_byte(v,b);
187
60620
  return res;
188
}
189
190
29274
bool f_i32(lbm_flat_value_t *v, int32_t w) {
191
29274
  bool res = true;
192

29274
  res = res && write_byte(v, S_I32_VALUE);
193

29274
  res = res && write_word(v, (uint32_t)w);
194
29274
  return res;
195
}
196
197
31122
bool f_u32(lbm_flat_value_t *v, uint32_t w) {
198
31122
  bool res = true;
199

31122
  res = res && write_byte(v, S_U32_VALUE);
200

31122
  res = res && write_word(v, w);
201
31122
  return res;
202
}
203
204
7640
bool f_float(lbm_flat_value_t *v, float f) {
205
7640
  bool res = true;
206

7640
  res = res && write_byte(v, S_FLOAT_VALUE);
207
  uint32_t u;
208
7640
  memcpy(&u, &f, sizeof(uint32_t));
209

7640
  res = res && write_word(v, (uint32_t)u);
210
7640
  return res;
211
}
212
213
28
bool f_double(lbm_flat_value_t *v, double d) {
214
28
  bool res = true;
215

28
  res = res && write_byte(v, S_DOUBLE_VALUE);
216
  uint64_t u;
217
28
  memcpy(&u, &d, sizeof(uint64_t));
218

28
  res = res && write_dword(v, u);
219
28
  return res;
220
}
221
222
28
bool f_i64(lbm_flat_value_t *v, int64_t w) {
223
28
  bool res = true;
224

28
  res = res && write_byte(v, S_I64_VALUE);
225

28
  res = res && write_dword(v, (uint64_t)w);
226
28
  return res;
227
}
228
229
28
bool f_u64(lbm_flat_value_t *v, uint64_t w) {
230
28
  bool res = true;
231

28
  res = res && write_byte(v, S_U64_VALUE);
232

28
  res = res && write_dword(v, w);
233
28
  return res;
234
}
235
236
// num_bytes is specifically an uint32_t
237
118748
bool f_lbm_array(lbm_flat_value_t *v, uint32_t num_bytes, uint8_t *data) {
238
118748
  bool res = write_byte(v, S_LBM_ARRAY);
239

118748
  res = res && write_word(v, num_bytes);
240

118748
  res = res && write_bytes(v, data, num_bytes);
241
118748
  return res;
242
}
243
244
static int flatten_maximum_depth = FLATTEN_VALUE_MAXIMUM_DEPTH;
245
246
28
void lbm_set_max_flatten_depth(int depth) {
247
28
  flatten_maximum_depth = depth;
248
28
}
249
250
28
void flatten_error(jmp_buf jb, int val) {
251
28
  longjmp(jb, val);
252
}
253
254
661962
int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth) {
255
661962
  if (depth > flatten_maximum_depth) {
256
28
    flatten_error(jb, FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH);
257
  }
258
259
661934
  lbm_uint t = lbm_type_of(v);
260

661934
  if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) {
261
    //  Clear constant bit, it is irrelevant to flattening
262
492940
    t = t & ~(LBM_PTR_TO_CONSTANT_BIT);
263
  }
264
265


661934
  switch (t) {
266
313600
  case LBM_TYPE_CONS: {
267
313600
    int res = 0;
268
313600
    int s1 = flatten_value_size_internal(jb,lbm_car(v), depth + 1);
269
313516
    if (s1 > 0) {
270
313516
      int s2 = flatten_value_size_internal(jb,lbm_cdr(v), depth + 1);
271
313516
      if (s2 > 0) {
272
313516
        res = (1 + s1 + s2);
273
      }
274
    }
275
313516
    return res;
276
  }
277
84
  case LBM_TYPE_LISPARRAY: {
278
84
    int sum = 4 + 1; // sizeof(uint32_t) + 1;
279
84
    lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v);
280
84
    lbm_value *arrdata = (lbm_value*)header->data;
281
84
    lbm_uint size = header->size / sizeof(lbm_value);
282
336
    for (lbm_uint i = 0; i < size; i ++ ) {
283
252
      sum += flatten_value_size_internal(jb, arrdata[i], depth + 1);
284
    }
285
84
    return sum;
286
  }
287
60620
  case LBM_TYPE_BYTE:
288
60620
    return 1 + 1;
289
45402
  case LBM_TYPE_U: /* fall through */
290
  case LBM_TYPE_I:
291
#ifndef LBM64
292
45402
    return 1 + 4;
293
#else
294
    return 1 + 8;
295
#endif
296
60452
  case LBM_TYPE_U32: /* fall through */
297
  case LBM_TYPE_I32:
298
  case LBM_TYPE_FLOAT:
299
60452
    return 1 + 4;
300
84
  case LBM_TYPE_U64: /* fall through */
301
  case LBM_TYPE_I64:
302
  case LBM_TYPE_DOUBLE:
303
84
    return 1 + 8;
304
62972
  case LBM_TYPE_SYMBOL: {
305
62972
    int s = f_sym_string_bytes(v);
306
62972
    if (s > 0) return 1 + s;
307
    flatten_error(jb, (int)s);
308
  } return 0; // already terminated with error
309
118692
  case LBM_TYPE_ARRAY: {
310
    // Platform dependent size.
311
    // TODO: Something needs to be done to these inconsistencies.
312
118692
    lbm_int s = lbm_heap_array_get_size(v);
313
118692
    if (s > 0)
314
118692
      return 1 + 4 + (int)s;
315
    flatten_error(jb, (int)s);
316
  } return 0; // already terminated with error
317
28
  default:
318
28
    return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
319
  }
320
}
321
322
34594
int flatten_value_size(lbm_value v, int depth) {
323
  jmp_buf jb;
324
34594
  int r = setjmp(jb);
325
34622
  if (r != 0) {
326
28
    return r;
327
  }
328
34594
  return flatten_value_size_internal(jb, v, depth);
329
}
330
331
661822
int flatten_value_c(lbm_flat_value_t *fv, lbm_value v) {
332
333
661822
  lbm_uint t = lbm_type_of(v);
334

661822
  if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) {
335
    //  Clear constant bit, it is irrelevant to flattening
336
492828
    t = t & ~(LBM_PTR_TO_CONSTANT_BIT);
337
  }
338
339



661822
  switch (t) {
340
313516
  case LBM_TYPE_CONS: {
341
313516
    bool res = true;
342

313516
    res = res && f_cons(fv);
343
313516
    if (res) {
344
313516
      int fv_r = flatten_value_c(fv, lbm_car(v));
345
313516
      if (fv_r == FLATTEN_VALUE_OK) {
346
313516
        fv_r = flatten_value_c(fv, lbm_cdr(v));
347
      }
348
313516
      return fv_r;
349
    }
350
  }break;
351
84
  case LBM_TYPE_LISPARRAY: {
352
84
    lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(v);
353
84
    lbm_value *arrdata = (lbm_value*)header->data;
354
84
    lbm_uint size = header->size / sizeof(lbm_value);
355
84
    if (!f_lisp_array(fv, size)) return FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY;
356
84
    int fv_r = FLATTEN_VALUE_OK;
357
336
    for (lbm_uint i = 0; i < size; i ++ ) {
358
252
      fv_r =  flatten_value_c(fv, arrdata[i]);
359
252
      if (fv_r != FLATTEN_VALUE_OK) {
360
        break;
361
      }
362
    }
363
84
    return fv_r;
364
  } break;
365
60620
  case LBM_TYPE_BYTE:
366
60620
    if (f_b(fv, (uint8_t)lbm_dec_as_char(v))) {
367
60620
      return FLATTEN_VALUE_OK;
368
    }
369
    break;
370
28
  case LBM_TYPE_U:
371
28
    if (f_u(fv, lbm_dec_u(v))) {
372
28
      return FLATTEN_VALUE_OK;
373
    }
374
    break;
375
45374
  case LBM_TYPE_I:
376
45374
    if (f_i(fv, lbm_dec_i(v))) {
377
45374
      return FLATTEN_VALUE_OK;
378
    }
379
    break;
380
31122
  case LBM_TYPE_U32:
381
31122
    if (f_u32(fv, lbm_dec_as_u32(v))) {
382
31122
      return FLATTEN_VALUE_OK;
383
    }
384
    break;
385
29274
  case LBM_TYPE_I32:
386
29274
    if (f_i32(fv, lbm_dec_as_i32(v))) {
387
29274
      return FLATTEN_VALUE_OK;
388
    }
389
    break;
390
28
  case LBM_TYPE_U64:
391
28
    if (f_u64(fv, lbm_dec_as_u64(v))) {
392
28
      return FLATTEN_VALUE_OK;
393
    }
394
    break;
395
28
  case LBM_TYPE_I64:
396
28
    if (f_i64(fv, lbm_dec_as_i64(v))) {
397
28
      return FLATTEN_VALUE_OK;
398
    }
399
    break;
400
56
  case LBM_TYPE_FLOAT:
401
56
    if (f_float(fv, lbm_dec_as_float(v))) {
402
56
      return FLATTEN_VALUE_OK;
403
    }
404
    break;
405
28
  case LBM_TYPE_DOUBLE:
406
28
    if (f_double(fv, lbm_dec_as_double(v))) {
407
28
      return FLATTEN_VALUE_OK;
408
    }
409
    break;
410
62972
  case LBM_TYPE_SYMBOL: {
411
62972
    char *sym_str = (char*)lbm_get_name_by_symbol(lbm_dec_sym(v));
412
62972
    if (f_sym_string(fv, sym_str)) {
413
62972
      return FLATTEN_VALUE_OK;
414
    }
415
  } break;
416
118692
  case LBM_TYPE_ARRAY: {
417
118692
    lbm_int s = lbm_heap_array_get_size(v);
418
118692
    const uint8_t *d = lbm_heap_array_get_data_ro(v);
419

118692
    if (s > 0 && d != NULL) {
420
118692
      if (f_lbm_array(fv, (uint32_t)s, (uint8_t*)d)) {
421
118692
        return FLATTEN_VALUE_OK;
422
      }
423
    } else {
424
      return FLATTEN_VALUE_ERROR_ARRAY;
425
    }
426
  }break;
427
  default:
428
    return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
429
  }
430
  return FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL;
431
}
432
433
56
lbm_value handle_flatten_error(int err_val) {
434

56
  switch (err_val) {
435
28
  case FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED:
436
28
    return ENC_SYM_EERROR;
437
  case FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL: /* fall through */
438
  case FLATTEN_VALUE_ERROR_FATAL:
439
    return ENC_SYM_FATAL_ERROR;
440
28
  case FLATTEN_VALUE_ERROR_CIRCULAR: /* fall through */
441
  case FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH:
442
28
    return ENC_SYM_EERROR;
443
  case FLATTEN_VALUE_ERROR_ARRAY: /* fall through */
444
  case FLATTEN_VALUE_ERROR_NOT_ENOUGH_MEMORY:
445
    return ENC_SYM_MERROR;
446
  }
447
  return ENC_SYM_NIL;
448
}
449
450
34596
lbm_value flatten_value(lbm_value v) {
451
452
34596
  lbm_value array_cell = lbm_heap_allocate_cell(LBM_TYPE_CONS, ENC_SYM_NIL, ENC_SYM_ARRAY_TYPE);
453
454
34596
  if (array_cell == ENC_SYM_MERROR) {
455
2
    return array_cell;
456
  }
457
458
  lbm_flat_value_t fv;
459
460
34594
  lbm_array_header_t *array = NULL;
461
34594
  int required_mem = flatten_value_size(v, 0);
462
34594
  if (required_mem > 0) {
463
34538
    array = (lbm_array_header_t *)lbm_malloc(sizeof(lbm_array_header_t));
464
34538
    if (array == NULL) {
465
      lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
466
      return ENC_SYM_MERROR;
467
    }
468
469
34538
    bool r = lbm_start_flatten(&fv, (lbm_uint)required_mem);
470
34538
    if (!r) {
471
      lbm_free(array);
472
      lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
473
      return ENC_SYM_MERROR;
474
    }
475
476
34538
    if (flatten_value_c(&fv, v) == FLATTEN_VALUE_OK) {
477
      // it would be wasteful to run finish_flatten here.
478
34538
      r = true;
479
    } else {
480
      r = false;
481
    }
482
483
34538
    if (r)  {
484
      // lift flat_value
485
34538
      array->data = (lbm_uint*)fv.buf;
486
34538
      array->size = fv.buf_size;
487
34538
      lbm_set_car(array_cell, (lbm_uint)array);
488
34538
      array_cell = lbm_set_ptr_type(array_cell, LBM_TYPE_ARRAY);
489
34538
      return array_cell;
490
    }
491
  }
492
56
  lbm_set_car_and_cdr(array_cell, ENC_SYM_NIL, ENC_SYM_NIL);
493
56
  return handle_flatten_error(required_mem);
494
}
495
496
// ------------------------------------------------------------
497
// Unflattening
498
61794
static bool extract_byte(lbm_flat_value_t *v, uint8_t *r) {
499
61794
  if (v->buf_size >= v->buf_pos + 1) {
500
61794
    *r = v->buf[v->buf_pos++];
501
61794
    return true;
502
  }
503
  return false;
504
}
505
506
241339
static bool extract_word(lbm_flat_value_t *v, uint32_t *r) {
507
241339
  bool res = false;
508
241339
  if (v->buf_size >= v->buf_pos + 4) {
509
241339
    uint32_t tmp = 0;
510
241339
    tmp |= (lbm_value)v->buf[v->buf_pos++];
511
241339
    tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
512
241339
    tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
513
241339
    tmp = tmp << 8 | (uint32_t)v->buf[v->buf_pos++];
514
241339
    *r = tmp;
515
241339
    res = true;
516
  }
517
241339
  return res;
518
}
519
520
84
static bool extract_dword(lbm_flat_value_t *v, uint64_t *r) {
521
84
  bool res = false;
522
84
  if (v->buf_size >= v->buf_pos + 8) {
523
84
    uint64_t tmp = 0;
524
84
    tmp |= (lbm_value)v->buf[v->buf_pos++];
525
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
526
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
527
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
528
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
529
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
530
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
531
84
    tmp = tmp << 8 | (uint64_t)v->buf[v->buf_pos++];
532
84
    *r = tmp;
533
84
    res = true;;
534
  }
535
84
  return res;
536
}
537
538
/* Recursive and potentially stack hungry for large flat values */
539
690831
static int lbm_unflatten_value_internal(lbm_flat_value_t *v, lbm_value *res) {
540
690831
  if (v->buf_size == v->buf_pos) return UNFLATTEN_MALFORMED;
541
542
690831
  uint8_t curr = v->buf[v->buf_pos++];
543
544




690831
  switch(curr) {
545
324092
  case S_CONS: {
546
    lbm_value a;
547
    lbm_value b;
548
324092
    int r = lbm_unflatten_value_internal(v, &a);
549
324092
    if (r == UNFLATTEN_OK) {
550
323682
      r = lbm_unflatten_value_internal(v, &b);
551
323682
      if (r == UNFLATTEN_OK) {
552
        lbm_value c;
553
320476
        c = lbm_cons(a,b);
554
320476
        if (lbm_is_symbol_merror(c)) return UNFLATTEN_GC_RETRY;
555
320234
        *res = c;
556
320234
        r = UNFLATTEN_OK;
557
      }
558
    }
559
323850
    return r;
560
  }
561
84
  case S_LBM_LISP_ARRAY: {
562
    uint32_t size;
563
84
    bool b = extract_word(v, &size);
564
84
    int r = UNFLATTEN_MALFORMED;
565
84
    if (b) {
566
      lbm_value array;
567
84
      lbm_heap_allocate_lisp_array(&array, size);
568
84
      lbm_array_header_t *header = (lbm_array_header_t*)lbm_car(array);
569
84
      lbm_value *arrdata = (lbm_value*)header->data;
570
84
      if (lbm_is_symbol_merror(array)) return UNFLATTEN_GC_RETRY;
571
      lbm_value a;
572
336
      for (uint32_t i = 0; i < size; i ++) {
573
252
        r = lbm_unflatten_value_internal(v, &a);
574
252
        if (r == UNFLATTEN_OK) {
575
252
          arrdata[i] = a;
576
        } else {
577
          break;
578
        }
579
      }
580
84
      *res = array;
581
    }
582
84
    return r;
583
  }
584
5889
  case S_SYM_VALUE: {
585
    lbm_uint tmp;
586
    bool b;
587
#ifndef LBM64
588
5889
    b = extract_word(v, &tmp);
589
#else
590
    b = extract_dword(v, &tmp);
591
#endif
592
5889
    if (b) {
593
5889
      *res = lbm_enc_sym(tmp);
594
5889
      return UNFLATTEN_OK;
595
    }
596
    return UNFLATTEN_MALFORMED;
597
  }
598
61794
  case S_BYTE_VALUE: {
599
    uint8_t tmp;
600
61794
    bool b = extract_byte(v, &tmp);
601
61794
    if (b) {
602
61794
      *res = lbm_enc_char((uint8_t)tmp);
603
61794
      return UNFLATTEN_OK;
604
    }
605
    return UNFLATTEN_MALFORMED;
606
  }
607
45668
  case S_I28_VALUE: {
608
    uint32_t tmp;
609
    bool b;
610
45668
    b = extract_word(v, &tmp);
611
45668
    if (b) {
612
45668
      *res = lbm_enc_i((int32_t)tmp);
613
45668
      return UNFLATTEN_OK;
614
    }
615
    return UNFLATTEN_MALFORMED;
616
  }
617
28
  case S_U28_VALUE: {
618
    uint32_t tmp;
619
    bool b;
620
28
    b = extract_word(v, &tmp);
621
28
    if (b) {
622
28
      *res = lbm_enc_u((uint32_t)tmp);
623
28
      return UNFLATTEN_OK;
624
    }
625
    return UNFLATTEN_MALFORMED;
626
  }
627
  case S_I56_VALUE: {
628
    uint64_t tmp;
629
    bool b;
630
    b = extract_dword(v, &tmp);
631
    if (b) {
632
#ifndef LBM64
633
      *res = lbm_enc_i64((int64_t)tmp);
634
#else
635
      *res = lbm_enc_i((int64_t)tmp);
636
#endif
637
      return UNFLATTEN_OK;
638
    }
639
    return UNFLATTEN_MALFORMED;
640
  }
641
  case S_U56_VALUE: {
642
    uint64_t tmp;
643
    bool b;
644
    b = extract_dword(v, &tmp);
645
    if (b) {
646
#ifndef LBM64
647
      *res = lbm_enc_u64(tmp);
648
#else
649
      *res = lbm_enc_u(tmp);
650
#endif
651
      return UNFLATTEN_OK;
652
    }
653
    return UNFLATTEN_MALFORMED;
654
  }
655
7634
  case S_FLOAT_VALUE: {
656
    uint32_t tmp;
657
    bool b;
658
7634
    b = extract_word(v, &tmp);
659
7634
    if (b) {
660
      lbm_float f;
661
7634
      memcpy(&f, &tmp, sizeof(lbm_float));
662
7634
      lbm_value im  = lbm_enc_float(f);
663
7634
      if (lbm_is_symbol_merror(im)) {
664
        return UNFLATTEN_GC_RETRY;
665
      }
666
7634
      *res = im;
667
7634
      return UNFLATTEN_OK;
668
    }
669
    return UNFLATTEN_MALFORMED;
670
  }
671
28
  case S_DOUBLE_VALUE: {
672
    uint64_t tmp;
673
    bool b;
674
28
    b = extract_dword(v, &tmp);
675
28
    if (b) {
676
      double f;
677
28
      memcpy(&f, &tmp, sizeof(uint64_t));
678
28
      lbm_value im  = lbm_enc_double(f);
679
28
      if (lbm_is_symbol_merror(im)) {
680
        return UNFLATTEN_GC_RETRY;
681
      }
682
28
      *res = im;
683
28
      return UNFLATTEN_OK;
684
    }
685
    return UNFLATTEN_MALFORMED;
686
  }
687
29562
  case S_I32_VALUE: {
688
   uint32_t tmp;
689
29562
    if (extract_word(v, &tmp)) {
690
29562
      lbm_value im = lbm_enc_i32((int32_t)tmp);
691
29562
      if (lbm_is_symbol_merror(im)) {
692
36
        return UNFLATTEN_GC_RETRY;
693
      }
694
29526
      *res = im;
695
29526
      return UNFLATTEN_OK;
696
    }
697
    return UNFLATTEN_MALFORMED;
698
  }
699
31766
  case S_U32_VALUE: {
700
    uint32_t tmp;
701
31766
    if (extract_word(v, &tmp)) {
702
31766
      lbm_value im = lbm_enc_u32(tmp);
703
31766
      if (lbm_is_symbol_merror(im)) {
704
14
        return UNFLATTEN_GC_RETRY;
705
      }
706
31752
      *res = im;
707
31752
      return UNFLATTEN_OK;
708
    }
709
    return UNFLATTEN_MALFORMED;
710
  }
711
28
  case S_I64_VALUE: {
712
28
   uint64_t tmp = 0;
713
28
    if (extract_dword(v, &tmp)) {
714
28
      lbm_value im = lbm_enc_i64((int64_t)tmp);
715
28
      if (lbm_is_symbol_merror(im)) {
716
        return UNFLATTEN_GC_RETRY;
717
      }
718
28
      *res = im;
719
28
      return UNFLATTEN_OK;
720
    }
721
    return UNFLATTEN_MALFORMED;
722
  }
723
28
  case S_U64_VALUE: {
724
28
    uint64_t tmp = 0;
725
28
    if (extract_dword(v, &tmp)) {
726
28
      lbm_value im = lbm_enc_u64(tmp);
727
28
      if (lbm_is_symbol_merror(im)) {
728
        return UNFLATTEN_GC_RETRY;
729
      }
730
28
      *res = im;
731
28
      return UNFLATTEN_OK;
732
    }
733
    return UNFLATTEN_MALFORMED;
734
  }
735
120708
  case S_LBM_ARRAY: {
736
    uint32_t num_elt;
737
120708
    if (extract_word(v, &num_elt)) {
738
120708
      if (lbm_heap_allocate_array(res, num_elt)) {
739
120348
        lbm_array_header_t *arr = (lbm_array_header_t*)lbm_car(*res);
740
120348
        lbm_uint num_bytes = num_elt;
741
120348
        memcpy(arr->data, v->buf + v->buf_pos, num_bytes);
742
120348
        v->buf_pos += num_bytes;
743
      } else {
744
360
        return UNFLATTEN_GC_RETRY;
745
      }
746
120348
      return UNFLATTEN_OK;
747
    }
748
    return UNFLATTEN_MALFORMED;
749
  }
750
63522
  case S_SYM_STRING: {
751
    lbm_uint sym_id;
752
63522
    if (lbm_add_symbol((char *)(v->buf + v->buf_pos), &sym_id)) {
753
63522
      lbm_uint num_bytes = strlen((char*)(v->buf + v->buf_pos)) + 1;
754
63522
      v->buf_pos += num_bytes;
755
63522
      *res = lbm_enc_sym(sym_id);
756
63522
      return UNFLATTEN_OK;
757
    }
758
    return UNFLATTEN_GC_RETRY;
759
  }
760
  default:
761
    return UNFLATTEN_MALFORMED;
762
  }
763
}
764
765
42153
bool lbm_unflatten_value(lbm_flat_value_t *v, lbm_value *res) {
766
42153
  bool b = false;
767
#ifdef LBM_ALWAYS_GC
768
  lbm_perform_gc();
769
#endif
770
42153
  int r = lbm_unflatten_value_internal(v,res);
771
42153
  if (r == UNFLATTEN_GC_RETRY) {
772
652
    lbm_perform_gc();
773
652
    v->buf_pos = 0;
774
652
    r = lbm_unflatten_value_internal(v,res);
775
  }
776
42153
  if (r == UNFLATTEN_MALFORMED) {
777
    *res = ENC_SYM_EERROR;
778
42153
  } else if (r == UNFLATTEN_GC_RETRY) {
779
    *res = ENC_SYM_MERROR;
780
  } else {
781
42153
    b = true;
782
  }
783
  // Do not free the flat value buffer here.
784
  // there are 2 cases:
785
  // 1: unflatten was called from lisp code -> GC removes the buffer.
786
  // 2: unflatten called from event processing -> event processor frees buffer.
787
42153
  return b;
788
}