GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/lbm_flat_value.c Lines: 418 491 85.1 %
Date: 2025-01-19 11:10:47 Branches: 186 315 59.0 %

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
41562
bool lbm_start_flatten(lbm_flat_value_t *v, size_t buffer_size) {
34
41562
  bool res = false;
35
41562
  uint8_t *data = lbm_malloc_reserve(buffer_size);
36
41562
  if (data) {
37
41562
    v->buf = data;
38
41562
    v->buf_size = buffer_size;
39
41562
    v->buf_pos = 0;
40
41562
    res = true;
41
  }
42
41562
  return res;
43
}
44
45
7024
bool lbm_finish_flatten(lbm_flat_value_t *v) {
46
  lbm_uint size_words;
47
7024
  if (v->buf_pos % sizeof(lbm_uint) == 0) {
48
    size_words = v->buf_pos / sizeof(lbm_uint);
49
  } else {
50
7024
    size_words = (v->buf_pos / sizeof(lbm_uint)) + 1;
51
  }
52
7024
  if (v->buf_size  <= size_words * sizeof(lbm_uint)) return true;
53
6996
  v->buf_size = size_words * sizeof(lbm_uint);
54
6996
  return (lbm_memory_shrink((lbm_uint*)v->buf, size_words) >= 0);
55
}
56
57
421886
static bool write_byte(lbm_flat_value_t *v, uint8_t b) {
58
421886
  bool res = false;
59
421886
  if (v->buf_size >= v->buf_pos + 1) {
60
421886
    v->buf[v->buf_pos++] = b;
61
421886
    res = true;
62
  }
63
421886
  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
237534
static bool write_word(lbm_flat_value_t *v, uint32_t w) {
77
237534
  bool res = false;
78
237534
  if (v->buf_size >= v->buf_pos + 4) {
79
237534
    v->buf[v->buf_pos++] = (uint8_t)(w >> 24);
80
237534
    v->buf[v->buf_pos++] = (uint8_t)(w >> 16);
81
237534
    v->buf[v->buf_pos++] = (uint8_t)(w >> 8);
82
237534
    v->buf[v->buf_pos++] = (uint8_t)w;
83
237534
    res = true;
84
  }
85
237534
  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
5399
bool f_sym(lbm_flat_value_t *v, lbm_uint sym_id) {
122
5399
  bool res = true;
123

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

5399
  res = res && write_word(v,sym_id);
126
  #else
127
  res = res && write_dword(v,sym_id);
128
  #endif
129
5399
  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
7505
bool f_float(lbm_flat_value_t *v, float f) {
205
7505
  bool res = true;
206

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

7505
  res = res && write_word(v, (uint32_t)u);
210
7505
  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
661934
int flatten_value_size_internal(jmp_buf jb, lbm_value v, int depth) {
255
661934
  if (depth > flatten_maximum_depth) {
256
28
    flatten_error(jb, FLATTEN_VALUE_ERROR_MAXIMUM_DEPTH);
257
  }
258
259
661906
  lbm_uint t = lbm_type_of(v);
260

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


661906
  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
    if (header) {
281
84
      lbm_value *arrdata = (lbm_value*)header->data;
282
84
      lbm_uint size = header->size / sizeof(lbm_value);
283
336
      for (lbm_uint i = 0; i < size; i ++ ) {
284
252
        sum += flatten_value_size_internal(jb, arrdata[i], depth + 1);
285
      }
286
    } else {
287
      flatten_error(jb, FLATTEN_VALUE_ERROR_ARRAY);
288
    }
289
84
    return sum;
290
  }
291
60620
  case LBM_TYPE_BYTE:
292
60620
    return 1 + 1;
293
45402
  case LBM_TYPE_U: /* fall through */
294
  case LBM_TYPE_I:
295
#ifndef LBM64
296
45402
    return 1 + 4;
297
#else
298
    return 1 + 8;
299
#endif
300
60452
  case LBM_TYPE_U32: /* fall through */
301
  case LBM_TYPE_I32:
302
  case LBM_TYPE_FLOAT:
303
60452
    return 1 + 4;
304
84
  case LBM_TYPE_U64: /* fall through */
305
  case LBM_TYPE_I64:
306
  case LBM_TYPE_DOUBLE:
307
84
    return 1 + 8;
308
62972
  case LBM_TYPE_SYMBOL: {
309
62972
    int s = f_sym_string_bytes(v);
310
62972
    if (s > 0) return 1 + s;
311
    flatten_error(jb, (int)s);
312
  } return 0; // already terminated with error
313
118692
  case LBM_TYPE_ARRAY: {
314
    // Platform dependent size.
315
    // TODO: Something needs to be done to these inconsistencies.
316
118692
    lbm_int s = lbm_heap_array_get_size(v);
317
118692
    if (s > 0)
318
118692
      return 1 + 4 + (int)s;
319
    flatten_error(jb, (int)s);
320
  } return 0; // already terminated with error
321
  default:
322
    return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
323
  }
324
}
325
326
34566
int flatten_value_size(lbm_value v, int depth) {
327
  jmp_buf jb;
328
34566
  int r = setjmp(jb);
329
34594
  if (r != 0) {
330
28
    return r;
331
  }
332
34566
  return flatten_value_size_internal(jb, v, depth);
333
}
334
335
661822
int flatten_value_c(lbm_flat_value_t *fv, lbm_value v) {
336
337
661822
  lbm_uint t = lbm_type_of(v);
338

661822
  if (t >= LBM_POINTER_TYPE_FIRST && t < LBM_POINTER_TYPE_LAST) {
339
    //  Clear constant bit, it is irrelevant to flattening
340
492828
    t = t & ~(LBM_PTR_TO_CONSTANT_BIT);
341
  }
342
343



661822
  switch (t) {
344
313516
  case LBM_TYPE_CONS: {
345
313516
    bool res = true;
346

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

118692
    if (s > 0 && d != NULL) {
428
118692
      if (f_lbm_array(fv, (uint32_t)s, (uint8_t*)d)) {
429
118692
        return FLATTEN_VALUE_OK;
430
      }
431
    } else {
432
      return FLATTEN_VALUE_ERROR_ARRAY;
433
    }
434
  }break;
435
  default:
436
    return FLATTEN_VALUE_ERROR_CANNOT_BE_FLATTENED;
437
  }
438
  return FLATTEN_VALUE_ERROR_BUFFER_TOO_SMALL;
439
}
440
441
28
lbm_value handle_flatten_error(int err_val) {
442

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




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