@mikrojs/native 0.12.0 → 0.14.0-pr-229.g0d8db1b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +3 -1
- package/deps/nanocbor/LICENSE +121 -0
- package/deps/nanocbor/include/nanocbor/config.h +87 -0
- package/deps/nanocbor/include/nanocbor/nanocbor.h +1012 -0
- package/deps/nanocbor/src/decoder.c +706 -0
- package/deps/nanocbor/src/encoder.c +418 -0
- package/deps/nanocbor/src/meson.build +12 -0
- package/include/mikrojs/mikrojs.h +7 -0
- package/include/mikrojs/platform.h +9 -0
- package/include/mikrojs/private.h +32 -5
- package/package.json +5 -2
- package/prebuilds/darwin-arm64/mikrojs.napi.node +0 -0
- package/prebuilds/linux-arm64/mikrojs.napi.node +0 -0
- package/prebuilds/linux-x64/mikrojs.napi.node +0 -0
- package/runtime/abort/abort.ts +120 -0
- package/runtime/internal.d.ts +2 -1
- package/runtime/sys/sys.ts +2 -0
- package/runtime/sys/types.ts +27 -1
- package/src/builtins.cpp +10 -5
- package/src/mik_abort.cpp +40 -107
- package/src/mik_console.cpp +26 -24
- package/src/mik_inspect.cpp +3 -3
- package/src/mik_repl.cpp +4 -0
- package/src/mik_sys.cpp +11 -1
- package/src/mikrojs.cpp +224 -78
- package/src/modules.cpp +7 -16
- package/src/platform_posix.cpp +5 -0
- package/LICENSE +0 -21
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-License-Identifier: CC0-1.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @ingroup nanocbor
|
|
7
|
+
* @{
|
|
8
|
+
* @file
|
|
9
|
+
* @brief Minimalistic CBOR encoder implementation
|
|
10
|
+
*
|
|
11
|
+
* @author Koen Zandberg <koen@bergzand.net>
|
|
12
|
+
* @}
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
#include <stddef.h>
|
|
16
|
+
#include <stdint.h>
|
|
17
|
+
#include <stdlib.h>
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
#include "nanocbor/config.h"
|
|
21
|
+
#include "nanocbor/nanocbor.h"
|
|
22
|
+
|
|
23
|
+
#include NANOCBOR_BYTEORDER_HEADER
|
|
24
|
+
|
|
25
|
+
/* memarray functions */
|
|
26
|
+
static bool _encoder_mem_fits(nanocbor_encoder_t *enc, void *ctx, size_t len)
|
|
27
|
+
{
|
|
28
|
+
(void)ctx;
|
|
29
|
+
return ((size_t)(enc->end - enc->cur) >= len);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static void _encoder_mem_append(nanocbor_encoder_t *enc, void *ctx, const uint8_t *data, size_t len)
|
|
33
|
+
{
|
|
34
|
+
(void)ctx;
|
|
35
|
+
memcpy(enc->cur, data, len);
|
|
36
|
+
enc->cur += len;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
void nanocbor_encoder_init(nanocbor_encoder_t *enc, uint8_t *buf, size_t len)
|
|
40
|
+
{
|
|
41
|
+
enc->len = 0;
|
|
42
|
+
enc->cur = buf;
|
|
43
|
+
enc->end = buf + len;
|
|
44
|
+
enc->append = _encoder_mem_append;
|
|
45
|
+
enc->fits = _encoder_mem_fits;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void nanocbor_encoder_stream_init(nanocbor_encoder_t *enc, void *ctx,
|
|
49
|
+
nanocbor_encoder_append append_func,
|
|
50
|
+
nanocbor_encoder_fits fits_func)
|
|
51
|
+
{
|
|
52
|
+
enc->len = 0;
|
|
53
|
+
enc->append = append_func;
|
|
54
|
+
enc->fits = fits_func;
|
|
55
|
+
enc->context = ctx;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
size_t nanocbor_encoded_len(nanocbor_encoder_t *enc)
|
|
59
|
+
{
|
|
60
|
+
return enc->len;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static inline void _incr_len(nanocbor_encoder_t *enc, size_t len)
|
|
64
|
+
{
|
|
65
|
+
enc->len += len;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static inline void _append(nanocbor_encoder_t *enc, const uint8_t *data, size_t len)
|
|
69
|
+
{
|
|
70
|
+
enc->append(enc, enc->context, data, len);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static inline int _fits(nanocbor_encoder_t *enc, size_t len)
|
|
74
|
+
{
|
|
75
|
+
return enc->fits(enc, enc->context, len) ? (int)len : NANOCBOR_ERR_END;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static int _fmt_single(nanocbor_encoder_t *enc, uint8_t single)
|
|
79
|
+
{
|
|
80
|
+
_incr_len(enc, 1);
|
|
81
|
+
int res = _fits(enc, 1);
|
|
82
|
+
|
|
83
|
+
if (res == 1) {
|
|
84
|
+
_append(enc, &single, 1);
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
return res;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
int nanocbor_fmt_bool(nanocbor_encoder_t *enc, bool content)
|
|
91
|
+
{
|
|
92
|
+
uint8_t single = NANOCBOR_MASK_FLOAT
|
|
93
|
+
| (content ? NANOCBOR_SIMPLE_TRUE : NANOCBOR_SIMPLE_FALSE);
|
|
94
|
+
|
|
95
|
+
return _fmt_single(enc, single);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static int _fmt_uint64(nanocbor_encoder_t *enc, uint64_t num, uint8_t type)
|
|
99
|
+
{
|
|
100
|
+
unsigned extrabytes = 0;
|
|
101
|
+
|
|
102
|
+
if (num < NANOCBOR_SIZE_BYTE) {
|
|
103
|
+
type |= num;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
if (num > UINT32_MAX) {
|
|
107
|
+
/* Requires long size */
|
|
108
|
+
type |= NANOCBOR_SIZE_LONG;
|
|
109
|
+
extrabytes = sizeof(uint64_t);
|
|
110
|
+
}
|
|
111
|
+
else if (num > UINT16_MAX) {
|
|
112
|
+
/* At least word size */
|
|
113
|
+
type |= NANOCBOR_SIZE_WORD;
|
|
114
|
+
extrabytes = sizeof(uint32_t);
|
|
115
|
+
}
|
|
116
|
+
else if (num > UINT8_MAX) {
|
|
117
|
+
type |= NANOCBOR_SIZE_SHORT;
|
|
118
|
+
extrabytes = sizeof(uint16_t);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
type |= NANOCBOR_SIZE_BYTE;
|
|
122
|
+
extrabytes = sizeof(uint8_t);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
_incr_len(enc, extrabytes + 1);
|
|
126
|
+
int res = _fits(enc, extrabytes + 1);
|
|
127
|
+
if (res > 0) {
|
|
128
|
+
_append(enc, &type, 1);
|
|
129
|
+
|
|
130
|
+
/* NOLINTNEXTLINE: user supplied function */
|
|
131
|
+
uint64_t benum = NANOCBOR_HTOBE64_FUNC(num);
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
_append(enc, (uint8_t *)&benum + sizeof(benum) - extrabytes,
|
|
135
|
+
extrabytes);
|
|
136
|
+
}
|
|
137
|
+
return res;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
int nanocbor_fmt_uint(nanocbor_encoder_t *enc, uint64_t num)
|
|
141
|
+
{
|
|
142
|
+
return _fmt_uint64(enc, num, NANOCBOR_MASK_UINT);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
int nanocbor_fmt_tag(nanocbor_encoder_t *enc, uint64_t num)
|
|
146
|
+
{
|
|
147
|
+
return _fmt_uint64(enc, num, NANOCBOR_MASK_TAG);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
int nanocbor_fmt_int(nanocbor_encoder_t *enc, int64_t num)
|
|
151
|
+
{
|
|
152
|
+
if (num < 0) {
|
|
153
|
+
/* Always negative at this point */
|
|
154
|
+
num = -(num + 1);
|
|
155
|
+
return _fmt_uint64(enc, (uint64_t)num, NANOCBOR_MASK_NINT);
|
|
156
|
+
}
|
|
157
|
+
return nanocbor_fmt_uint(enc, (uint64_t)num);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
int nanocbor_fmt_simple(nanocbor_encoder_t *enc, uint8_t value)
|
|
161
|
+
{
|
|
162
|
+
/* Exclude assigned or reserved simple values between 20 and 31 */
|
|
163
|
+
if (value >= NANOCBOR_SIMPLE_FALSE && value <= NANOCBOR_SIZE_INDEFINITE) {
|
|
164
|
+
return NANOCBOR_ERR_INVALID_TYPE;
|
|
165
|
+
}
|
|
166
|
+
return _fmt_uint64(enc, value, NANOCBOR_MASK_FLOAT);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
int nanocbor_fmt_bstr(nanocbor_encoder_t *enc, size_t len)
|
|
170
|
+
{
|
|
171
|
+
return _fmt_uint64(enc, (uint64_t)len, NANOCBOR_MASK_BSTR);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
int nanocbor_fmt_tstr(nanocbor_encoder_t *enc, size_t len)
|
|
175
|
+
{
|
|
176
|
+
return _fmt_uint64(enc, (uint64_t)len, NANOCBOR_MASK_TSTR);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static int _put_bytes(nanocbor_encoder_t *enc, const uint8_t *str, size_t len)
|
|
180
|
+
{
|
|
181
|
+
_incr_len(enc, len);
|
|
182
|
+
int res = _fits(enc, len);
|
|
183
|
+
|
|
184
|
+
if (res >= 0) {
|
|
185
|
+
_append(enc, str, len);
|
|
186
|
+
return NANOCBOR_OK;
|
|
187
|
+
}
|
|
188
|
+
return res;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
int nanocbor_put_tstr(nanocbor_encoder_t *enc, const char *str)
|
|
192
|
+
{
|
|
193
|
+
size_t len = strlen(str);
|
|
194
|
+
|
|
195
|
+
nanocbor_fmt_tstr(enc, len);
|
|
196
|
+
return _put_bytes(enc, (const uint8_t *)str, len);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
int nanocbor_put_tstrn(nanocbor_encoder_t *enc, const char *str, size_t len)
|
|
200
|
+
{
|
|
201
|
+
nanocbor_fmt_tstr(enc, len);
|
|
202
|
+
return _put_bytes(enc, (const uint8_t *)str, len);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
int nanocbor_put_bstr(nanocbor_encoder_t *enc, const uint8_t *str, size_t len)
|
|
206
|
+
{
|
|
207
|
+
nanocbor_fmt_bstr(enc, len);
|
|
208
|
+
return _put_bytes(enc, str, len);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
int nanocbor_fmt_array(nanocbor_encoder_t *enc, size_t len)
|
|
212
|
+
{
|
|
213
|
+
return _fmt_uint64(enc, (uint64_t)len, NANOCBOR_MASK_ARR);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
int nanocbor_fmt_map(nanocbor_encoder_t *enc, size_t len)
|
|
217
|
+
{
|
|
218
|
+
return _fmt_uint64(enc, (uint64_t)len, NANOCBOR_MASK_MAP);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
int nanocbor_fmt_array_indefinite(nanocbor_encoder_t *enc)
|
|
222
|
+
{
|
|
223
|
+
return _fmt_single(enc, NANOCBOR_MASK_ARR | NANOCBOR_SIZE_INDEFINITE);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
int nanocbor_fmt_map_indefinite(nanocbor_encoder_t *enc)
|
|
227
|
+
{
|
|
228
|
+
return _fmt_single(enc, NANOCBOR_MASK_MAP | NANOCBOR_SIZE_INDEFINITE);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
int nanocbor_fmt_end_indefinite(nanocbor_encoder_t *enc)
|
|
232
|
+
{
|
|
233
|
+
/* End is marked with float major and indefinite minor number */
|
|
234
|
+
return _fmt_single(enc, NANOCBOR_MASK_FLOAT | NANOCBOR_SIZE_INDEFINITE);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
int nanocbor_fmt_null(nanocbor_encoder_t *enc)
|
|
238
|
+
{
|
|
239
|
+
return _fmt_single(enc, NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_NULL);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
int nanocbor_fmt_undefined(nanocbor_encoder_t *enc)
|
|
243
|
+
{
|
|
244
|
+
return _fmt_single(enc, NANOCBOR_MASK_FLOAT | NANOCBOR_SIMPLE_UNDEF);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Double bit mask related defines */
|
|
248
|
+
#define DOUBLE_EXP_OFFSET (1023U)
|
|
249
|
+
#define DOUBLE_SIZE (64U)
|
|
250
|
+
#define DOUBLE_EXP_POS (52U)
|
|
251
|
+
#define DOUBLE_SIGN_POS (63U)
|
|
252
|
+
#define DOUBLE_EXP_MASK ((uint64_t)0x7FFU)
|
|
253
|
+
#define DOUBLE_SIGN_MASK ((uint64_t)1U << DOUBLE_SIGN_POS)
|
|
254
|
+
#define DOUBLE_EXP_IS_NAN (0x7FFU)
|
|
255
|
+
#define DOUBLE_IS_ZERO (~(DOUBLE_SIGN_MASK))
|
|
256
|
+
#define DOUBLE_FLOAT_LOSS (0x1FFFFFFFU)
|
|
257
|
+
|
|
258
|
+
/* float bit mask related defines */
|
|
259
|
+
#define FLOAT_EXP_OFFSET (127U)
|
|
260
|
+
#define FLOAT_SIZE (32U)
|
|
261
|
+
#define FLOAT_EXP_POS (23U)
|
|
262
|
+
#define FLOAT_EXP_MASK ((uint32_t)0xFFU)
|
|
263
|
+
#define FLOAT_SIGN_POS (31U)
|
|
264
|
+
#define FLOAT_FRAC_MASK (0x7FFFFFU)
|
|
265
|
+
#define FLOAT_SIGN_MASK ((uint32_t)1U << FLOAT_SIGN_POS)
|
|
266
|
+
#define FLOAT_EXP_IS_NAN (0xFFU)
|
|
267
|
+
#define FLOAT_IS_ZERO (~(FLOAT_SIGN_MASK))
|
|
268
|
+
/* Part where a float to halffloat leads to precision loss */
|
|
269
|
+
#define FLOAT_HALF_LOSS (0x1FFFU)
|
|
270
|
+
|
|
271
|
+
/* halffloat bit mask related defines */
|
|
272
|
+
#define HALF_EXP_OFFSET (15U)
|
|
273
|
+
#define HALF_SIZE (16U)
|
|
274
|
+
#define HALF_EXP_POS (10U)
|
|
275
|
+
#define HALF_EXP_MASK (0x1FU)
|
|
276
|
+
#define HALF_SIGN_POS (15U)
|
|
277
|
+
#define HALF_FRAC_MASK (0x3FFU)
|
|
278
|
+
#define HALF_SIGN_MASK ((uint16_t)(1U << HALF_SIGN_POS))
|
|
279
|
+
#define HALF_MASK_HALF (0xFFU)
|
|
280
|
+
|
|
281
|
+
/* Check special cases for single precision floats */
|
|
282
|
+
static bool _single_is_inf_nan(uint8_t exp)
|
|
283
|
+
{
|
|
284
|
+
return exp == FLOAT_EXP_IS_NAN;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static bool _single_is_zero(uint32_t num)
|
|
288
|
+
{
|
|
289
|
+
return (num & FLOAT_IS_ZERO) == 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
static bool _single_in_range(uint8_t exp, uint32_t num)
|
|
293
|
+
{
|
|
294
|
+
/* Check if lower 13 bits of fraction are zero, if so we might be able to
|
|
295
|
+
* convert without precision loss */
|
|
296
|
+
if (exp <= (HALF_EXP_OFFSET + FLOAT_EXP_OFFSET)
|
|
297
|
+
&& exp >= ((-HALF_EXP_OFFSET + 1) + FLOAT_EXP_OFFSET)
|
|
298
|
+
&& ((num & FLOAT_HALF_LOSS) == 0)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static int _fmt_halffloat(nanocbor_encoder_t *enc, uint16_t half)
|
|
305
|
+
{
|
|
306
|
+
_incr_len(enc, sizeof(uint16_t) + 1);
|
|
307
|
+
int res = _fits(enc, sizeof(uint16_t) + 1);
|
|
308
|
+
if (res > 0) {
|
|
309
|
+
uint8_t tmp[3] = {
|
|
310
|
+
NANOCBOR_MASK_FLOAT | NANOCBOR_SIZE_SHORT,
|
|
311
|
+
(half >> HALF_SIZE / 2),
|
|
312
|
+
half & HALF_MASK_HALF };
|
|
313
|
+
_append(enc, tmp, sizeof(tmp));
|
|
314
|
+
res = sizeof(uint16_t) + 1;
|
|
315
|
+
}
|
|
316
|
+
return res;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#if __SIZEOF_DOUBLE__ != __SIZEOF_FLOAT__
|
|
320
|
+
/* Check special cases for single precision floats */
|
|
321
|
+
static bool _double_is_inf_nan(uint16_t exp)
|
|
322
|
+
{
|
|
323
|
+
return (exp == DOUBLE_EXP_IS_NAN);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static bool _double_is_zero(uint64_t num)
|
|
327
|
+
{
|
|
328
|
+
return (num & DOUBLE_IS_ZERO) == 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
static bool _double_in_range(uint16_t exp, uint64_t num)
|
|
332
|
+
{
|
|
333
|
+
/* Check if lower 13 bits of fraction are zero, if so we might be able to
|
|
334
|
+
* convert without precision loss */
|
|
335
|
+
if (exp <= (DOUBLE_EXP_OFFSET + FLOAT_EXP_OFFSET)
|
|
336
|
+
&& exp >= (DOUBLE_EXP_OFFSET - FLOAT_EXP_OFFSET + 1)
|
|
337
|
+
&& ((num & DOUBLE_FLOAT_LOSS) == 0)) { /* First 29 bits must be zero */
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
#endif
|
|
343
|
+
|
|
344
|
+
int nanocbor_fmt_float(nanocbor_encoder_t *enc, float num)
|
|
345
|
+
{
|
|
346
|
+
/* Allow bitwise access to float */
|
|
347
|
+
uint32_t *unum = (uint32_t *)#
|
|
348
|
+
|
|
349
|
+
/* Retrieve exponent */
|
|
350
|
+
uint8_t exp = (*unum >> FLOAT_EXP_POS) & FLOAT_EXP_MASK;
|
|
351
|
+
if (_single_is_inf_nan(exp) || _single_is_zero(*unum)
|
|
352
|
+
|| _single_in_range(exp, *unum)) {
|
|
353
|
+
/* Copy sign bit */
|
|
354
|
+
uint16_t half = ((*unum >> (FLOAT_SIZE - HALF_SIZE)) & HALF_SIGN_MASK);
|
|
355
|
+
/* Shift exponent */
|
|
356
|
+
if (exp != FLOAT_EXP_IS_NAN && exp != 0) {
|
|
357
|
+
exp = exp + (uint8_t)(HALF_EXP_OFFSET - FLOAT_EXP_OFFSET);
|
|
358
|
+
}
|
|
359
|
+
/* Add exponent */
|
|
360
|
+
half |= ((exp & HALF_EXP_MASK) << HALF_EXP_POS)
|
|
361
|
+
| ((*unum >> (FLOAT_EXP_POS - HALF_EXP_POS)) & HALF_FRAC_MASK);
|
|
362
|
+
return _fmt_halffloat(enc, half);
|
|
363
|
+
}
|
|
364
|
+
/* normal float */
|
|
365
|
+
_incr_len(enc, sizeof(float) + 1);
|
|
366
|
+
int res = _fits(enc, 1 + sizeof(float));
|
|
367
|
+
if (res > 0) {
|
|
368
|
+
const uint8_t tmp = NANOCBOR_MASK_FLOAT | NANOCBOR_SIZE_WORD;
|
|
369
|
+
_append(enc, &tmp, sizeof(tmp));
|
|
370
|
+
/* NOLINTNEXTLINE: user supplied function */
|
|
371
|
+
uint32_t bnum = NANOCBOR_HTOBE32_FUNC(*unum);
|
|
372
|
+
_append(enc, (uint8_t*)&bnum, sizeof(bnum));
|
|
373
|
+
}
|
|
374
|
+
return res;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
int nanocbor_fmt_double(nanocbor_encoder_t *enc, double num)
|
|
378
|
+
{
|
|
379
|
+
#if __SIZEOF_DOUBLE__ == __SIZEOF_FLOAT__
|
|
380
|
+
return nanocbor_fmt_float(enc, num);
|
|
381
|
+
#else
|
|
382
|
+
uint64_t *unum = (uint64_t *)#
|
|
383
|
+
uint16_t exp = (*unum >> DOUBLE_EXP_POS) & DOUBLE_EXP_MASK;
|
|
384
|
+
if (_double_is_inf_nan(exp) || _double_is_zero(*unum)
|
|
385
|
+
|| _double_in_range(exp, *unum)) {
|
|
386
|
+
/* copy sign bit over */
|
|
387
|
+
uint32_t single
|
|
388
|
+
= (*unum >> (DOUBLE_SIZE - FLOAT_SIZE)) & (FLOAT_SIGN_MASK);
|
|
389
|
+
/* Shift exponent */
|
|
390
|
+
if (exp != DOUBLE_EXP_IS_NAN && exp != 0) {
|
|
391
|
+
exp = exp + FLOAT_EXP_OFFSET - DOUBLE_EXP_OFFSET;
|
|
392
|
+
}
|
|
393
|
+
single |= ((exp & FLOAT_EXP_MASK) << FLOAT_EXP_POS)
|
|
394
|
+
| ((*unum >> (DOUBLE_EXP_POS - FLOAT_EXP_POS)) & FLOAT_FRAC_MASK);
|
|
395
|
+
float *fsingle = (float *)&single;
|
|
396
|
+
return nanocbor_fmt_float(enc, *fsingle);
|
|
397
|
+
}
|
|
398
|
+
_incr_len(enc, sizeof(double) + 1);
|
|
399
|
+
int res = _fits(enc, 1 + sizeof(double));
|
|
400
|
+
if (res > 0) {
|
|
401
|
+
const uint8_t tmp = NANOCBOR_MASK_FLOAT | NANOCBOR_SIZE_LONG;
|
|
402
|
+
_append(enc, &tmp, 1);
|
|
403
|
+
/* NOLINTNEXTLINE: user supplied function */
|
|
404
|
+
uint64_t bnum = NANOCBOR_HTOBE64_FUNC(*unum);
|
|
405
|
+
_append(enc, (uint8_t*)&bnum, sizeof(bnum));
|
|
406
|
+
}
|
|
407
|
+
return res;
|
|
408
|
+
#endif
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
int nanocbor_fmt_decimal_frac(nanocbor_encoder_t *enc, int32_t e, int32_t m)
|
|
412
|
+
{
|
|
413
|
+
int res = nanocbor_fmt_tag(enc, NANOCBOR_TAG_DEC_FRAC);
|
|
414
|
+
res += nanocbor_fmt_array(enc, 2);
|
|
415
|
+
res += nanocbor_fmt_int(enc, e);
|
|
416
|
+
res += nanocbor_fmt_int(enc, m);
|
|
417
|
+
return res;
|
|
418
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
decoder_source = files('decoder.c')
|
|
2
|
+
encoder_source = files('encoder.c')
|
|
3
|
+
|
|
4
|
+
project_sources += decoder_source
|
|
5
|
+
project_sources += encoder_source
|
|
6
|
+
|
|
7
|
+
encoder_lib = static_library('encoder',
|
|
8
|
+
encoder_source,
|
|
9
|
+
include_directories : inc)
|
|
10
|
+
decoder_lib = static_library('decoder',
|
|
11
|
+
decoder_source,
|
|
12
|
+
include_directories : inc)
|
|
@@ -86,6 +86,13 @@ void MIK_FreeRuntime(MIKRuntime* mik_rt);
|
|
|
86
86
|
* Emits no diagnostic output — callers decide whether and how to log. */
|
|
87
87
|
int MIK_RunEntry(MIKRuntime* mik_rt, const char* entry);
|
|
88
88
|
|
|
89
|
+
/* MIK_RunEntry variant that, on -EFAULT, copies the thrown exception's
|
|
90
|
+
* string form (or the sync-rejected promise's rejection value) into
|
|
91
|
+
* err_buf so callers can surface the real failure instead of a generic
|
|
92
|
+
* "evaluation threw". err_buf may be NULL; when given it is always
|
|
93
|
+
* NUL-terminated (empty when no message could be captured). */
|
|
94
|
+
int MIK_RunEntryErr(MIKRuntime* mik_rt, const char* entry, char* err_buf, size_t err_buf_size);
|
|
95
|
+
|
|
89
96
|
JSContext* MIK_GetJSContext(MIKRuntime* mik_rt);
|
|
90
97
|
MIKRuntime* MIK_GetRuntime(JSContext* ctx);
|
|
91
98
|
void MIK_SetFSBasePath(MIKRuntime* mik_rt, const char* base_path);
|
|
@@ -64,6 +64,15 @@ typedef struct MIKPlatform {
|
|
|
64
64
|
* original 6 MAC bytes. The returned pointer must remain valid for the
|
|
65
65
|
* lifetime of the platform. */
|
|
66
66
|
const char* (*get_device_id)(void);
|
|
67
|
+
/** Reason the chip last reset, as a stable lowercase string. On ESP32
|
|
68
|
+
* this maps esp_reset_reason(): "power-on", "software", "panic",
|
|
69
|
+
* "watchdog", "interrupt-watchdog", "task-watchdog", "brownout",
|
|
70
|
+
* "deep-sleep", "external", "sdio", "usb", "jtag", "efuse",
|
|
71
|
+
* "power-glitch", "cpu-lockup", or "unknown". A clean restart()
|
|
72
|
+
* reports "software". Host platforms have no reset concept and return
|
|
73
|
+
* "unknown". The returned pointer must remain valid for the lifetime
|
|
74
|
+
* of the platform. */
|
|
75
|
+
const char* (*get_reset_reason)(void);
|
|
67
76
|
} MIKPlatform;
|
|
68
77
|
|
|
69
78
|
/* Log levels (matching ESP-IDF ESP_LOG_xxx values) */
|
|
@@ -48,6 +48,15 @@ struct MIKLoopConsumerEntry {
|
|
|
48
48
|
MIKLoopDestroyFn destroy_fn;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
/* A promise that rejected without a handler, awaiting the end-of-turn
|
|
52
|
+
* unhandled-rejection check. Mirrors quickjs-libc's JSRejectedPromiseEntry:
|
|
53
|
+
* we hold a reference to both the promise (matched by identity on `handle`)
|
|
54
|
+
* and its reason (reported at flush time). */
|
|
55
|
+
struct MIKRejectedPromise {
|
|
56
|
+
JSValue promise;
|
|
57
|
+
JSValue reason;
|
|
58
|
+
};
|
|
59
|
+
|
|
51
60
|
struct MIKRuntime {
|
|
52
61
|
MIKRunOptions options;
|
|
53
62
|
MIKConfig config;
|
|
@@ -83,10 +92,16 @@ struct MIKRuntime {
|
|
|
83
92
|
MIKTimerRegistry* timers;
|
|
84
93
|
std::vector<MIKNativeModuleEntry> native_modules;
|
|
85
94
|
std::vector<MIKLoopConsumerEntry> loop_consumers;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
/* Promises that rejected without a handler, awaiting the end-of-turn
|
|
96
|
+
* unhandled-rejection check. The host rejection tracker adds a promise
|
|
97
|
+
* here on `reject` and removes it on `handle`; whatever remains after a
|
|
98
|
+
* microtask drain (mik__execute_jobs) is a genuine unhandled rejection
|
|
99
|
+
* and gets reported. This deferral mirrors the HTML/WinterCG algorithm
|
|
100
|
+
* and is what prevents a transiently-unhandled promise (e.g. a module's
|
|
101
|
+
* evaluation promise, rejected before the import loader attaches its
|
|
102
|
+
* .then) from being reported. Entries hold dup'd references owned by this
|
|
103
|
+
* vector and freed when removed or flushed. */
|
|
104
|
+
std::vector<MIKRejectedPromise> pending_rejections;
|
|
90
105
|
/* Shared prototype for Result objects ({ok, value} / {ok, error}) created
|
|
91
106
|
* by mik__result_ok/mik__result_err and the native:result ok()/err()
|
|
92
107
|
* functions. Holds .map/.mapErr/.andThen/.match/.orDefault/.orPanic +
|
|
@@ -167,6 +182,10 @@ JSValue mik_new_error(JSContext* ctx, int err);
|
|
|
167
182
|
JSValue mik_throw_errno(JSContext* ctx, int err);
|
|
168
183
|
|
|
169
184
|
void mik__execute_jobs(JSContext* ctx);
|
|
185
|
+
/* End-of-turn unhandled-rejection check; called after each microtask drain. */
|
|
186
|
+
void mik__flush_unhandled_rejections(JSContext* ctx);
|
|
187
|
+
/* Drop a promise from the pending-rejection queue without reporting it. */
|
|
188
|
+
void mik__forget_rejection(JSContext* ctx, JSValue promise);
|
|
170
189
|
JSModuleDef* mik__load_builtin(JSContext* ctx, const char* name);
|
|
171
190
|
int mik__load_file(JSContext* ctx, DynBuf* dbuf, const char* filename);
|
|
172
191
|
void mik__resolve_fs_path(JSContext* ctx, const char* module_name, char* out, size_t out_size);
|
|
@@ -221,7 +240,10 @@ void mik__stdin_consume(JSContext* ctx);
|
|
|
221
240
|
|
|
222
241
|
/* Console global (mik_console.cpp) */
|
|
223
242
|
void mik__console_init(JSContext* ctx, JSValue global_obj);
|
|
224
|
-
|
|
243
|
+
/* Reports an uncaught error/rejection. Dedups by error-object identity:
|
|
244
|
+
* returns true if it reported, false if this same object was already
|
|
245
|
+
* reported. */
|
|
246
|
+
bool mik__report_uncaught(JSContext* ctx, JSValue exc, bool in_promise = false);
|
|
225
247
|
|
|
226
248
|
/* Inspect (mik_inspect.cpp) */
|
|
227
249
|
std::string mik_inspect(JSContext* ctx, JSValue value, int depth = 2, bool colors = false,
|
|
@@ -313,6 +335,11 @@ void mik__repl_set_paused(bool paused);
|
|
|
313
335
|
* Device replies with zero-or-more MIK_MSG_FS_CHUNK frames followed by
|
|
314
336
|
* MIK_MSG_OK on EOF, or MIK_MSG_ERR if the path can't be opened. */
|
|
315
337
|
#define MIK_CMD_FS_GET 0x2B
|
|
338
|
+
/* Clear the on-device log files (log.txt + log.txt.1). No payload.
|
|
339
|
+
* Device suspends the logger, deletes both files, reopens a fresh
|
|
340
|
+
* log.txt, and replies MIK_MSG_OK. No-op (still OK) when file logging
|
|
341
|
+
* is disabled. */
|
|
342
|
+
#define MIK_CMD_LOG_RESET 0x2C
|
|
316
343
|
|
|
317
344
|
#define MIK_CMD_CONFIG_LIST 0x40
|
|
318
345
|
#define MIK_CMD_CONFIG_SET 0x41
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikrojs/native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-pr-229.g0d8db1b",
|
|
4
4
|
"description": "Mikro.js C++ runtime library and Node.js native addon",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"esp32",
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
"cmake",
|
|
26
26
|
"cmake.js",
|
|
27
27
|
"CMakeLists.txt",
|
|
28
|
+
"deps/nanocbor/src",
|
|
29
|
+
"deps/nanocbor/include",
|
|
30
|
+
"deps/nanocbor/LICENSE",
|
|
28
31
|
"include",
|
|
29
32
|
"runtime",
|
|
30
33
|
"scripts",
|
|
@@ -80,7 +83,7 @@
|
|
|
80
83
|
"cmake-js": "^8.0.0",
|
|
81
84
|
"node-addon-api": "^8.7.0",
|
|
82
85
|
"node-gyp-build": "^4.8.4",
|
|
83
|
-
"@mikrojs/quickjs": "0.
|
|
86
|
+
"@mikrojs/quickjs": "0.14.0-pr-229.g0d8db1b"
|
|
84
87
|
},
|
|
85
88
|
"devDependencies": {
|
|
86
89
|
"@swc/core": "^1.15.30",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* Minimal AbortController / AbortSignal implementation.
|
|
2
|
+
*
|
|
3
|
+
* This is a lightweight subset of the WHATWG DOM spec: just enough
|
|
4
|
+
* for fetch timeouts and cooperative cancellation. No EventTarget
|
|
5
|
+
* dependency: listeners are stored in a simple array.
|
|
6
|
+
*
|
|
7
|
+
* Evaluating this module installs AbortController, AbortSignal,
|
|
8
|
+
* AbortError, and TimeoutError on globalThis. It is loaded lazily by
|
|
9
|
+
* the native lazy getters in mik_abort.cpp on first access to any of
|
|
10
|
+
* the four globals; shipping it as precompiled bytecode keeps the
|
|
11
|
+
* QuickJS parser out of the install path (parsing at runtime caused
|
|
12
|
+
* OOM on low-memory chips).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
class AbortError extends Error {
|
|
16
|
+
constructor(message?: string) {
|
|
17
|
+
super(message || 'The operation was aborted')
|
|
18
|
+
}
|
|
19
|
+
get name() {
|
|
20
|
+
return 'AbortError'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class TimeoutError extends Error {
|
|
25
|
+
constructor(message?: string) {
|
|
26
|
+
super(message || 'The operation timed out')
|
|
27
|
+
}
|
|
28
|
+
get name() {
|
|
29
|
+
return 'TimeoutError'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const _a: unique symbol = Symbol()
|
|
34
|
+
const _r: unique symbol = Symbol()
|
|
35
|
+
const _l: unique symbol = Symbol()
|
|
36
|
+
const _s: unique symbol = Symbol()
|
|
37
|
+
|
|
38
|
+
function doAbort(signal: AbortSignal, reason: unknown): void {
|
|
39
|
+
if (signal[_a]) return
|
|
40
|
+
signal[_a] = true
|
|
41
|
+
signal[_r] = reason
|
|
42
|
+
if (typeof signal.onabort === 'function') signal.onabort()
|
|
43
|
+
for (const fn of signal[_l]) fn()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class AbortSignal {
|
|
47
|
+
[_a] = false;
|
|
48
|
+
[_r]: unknown = undefined;
|
|
49
|
+
[_l]: (() => void)[] = []
|
|
50
|
+
onabort: (() => void) | null = null
|
|
51
|
+
|
|
52
|
+
get aborted(): boolean {
|
|
53
|
+
return this[_a]
|
|
54
|
+
}
|
|
55
|
+
get reason(): unknown {
|
|
56
|
+
return this[_r]
|
|
57
|
+
}
|
|
58
|
+
throwIfAborted(): void {
|
|
59
|
+
if (this[_a]) throw this[_r]
|
|
60
|
+
}
|
|
61
|
+
addEventListener(type: 'abort', fn: () => void): void {
|
|
62
|
+
if (type === 'abort' && typeof fn === 'function') this[_l].push(fn)
|
|
63
|
+
}
|
|
64
|
+
removeEventListener(type: 'abort', fn: () => void): void {
|
|
65
|
+
if (type === 'abort') this[_l] = this[_l].filter((f) => f !== fn)
|
|
66
|
+
}
|
|
67
|
+
static abort(reason?: unknown): AbortSignal {
|
|
68
|
+
const s = new AbortSignal()
|
|
69
|
+
doAbort(s, reason !== undefined ? reason : new AbortError())
|
|
70
|
+
return s
|
|
71
|
+
}
|
|
72
|
+
static timeout(ms: number): AbortSignal {
|
|
73
|
+
const s = new AbortSignal()
|
|
74
|
+
setTimeout(() => doAbort(s, new TimeoutError()), ms)
|
|
75
|
+
return s
|
|
76
|
+
}
|
|
77
|
+
static any(signals: AbortSignal[]): AbortSignal {
|
|
78
|
+
const s = new AbortSignal()
|
|
79
|
+
for (const i of signals) {
|
|
80
|
+
if (i.aborted) {
|
|
81
|
+
doAbort(s, i.reason)
|
|
82
|
+
return s
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const i of signals) {
|
|
86
|
+
i.addEventListener('abort', () => doAbort(s, i.reason))
|
|
87
|
+
}
|
|
88
|
+
return s
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
class AbortController {
|
|
93
|
+
[_s] = new AbortSignal()
|
|
94
|
+
|
|
95
|
+
get signal(): AbortSignal {
|
|
96
|
+
return this[_s]
|
|
97
|
+
}
|
|
98
|
+
abort(reason?: unknown): void {
|
|
99
|
+
doAbort(this[_s], reason !== undefined ? reason : new AbortError())
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Object.defineProperties, NOT Object.assign: when this module is
|
|
104
|
+
* evaluated via a direct `import 'mikro/abort'` (it is in the builtins
|
|
105
|
+
* table), the four lazy getters installed by mik_abort.cpp are still
|
|
106
|
+
* present as setter-less accessors, and Object.assign's [[Set]] would
|
|
107
|
+
* throw "no setter for property". Defining replaces the accessors with
|
|
108
|
+
* plain data properties, matching what the lazy-getter path produces. */
|
|
109
|
+
const descriptor = (value: unknown) => ({
|
|
110
|
+
value,
|
|
111
|
+
writable: true,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
})
|
|
115
|
+
Object.defineProperties(globalThis, {
|
|
116
|
+
AbortError: descriptor(AbortError),
|
|
117
|
+
TimeoutError: descriptor(TimeoutError),
|
|
118
|
+
AbortSignal: descriptor(AbortSignal),
|
|
119
|
+
AbortController: descriptor(AbortController),
|
|
120
|
+
})
|