@mikrojs/native 0.0.7
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 +198 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/cmake/mikrojs_bytecode.cmake +146 -0
- package/cmake.js +22 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/include/byteorder_apple.h +11 -0
- package/include/byteorder_windows.h +12 -0
- package/include/mikrojs/cbor_helpers.h +24 -0
- package/include/mikrojs/cutils_wrap.h +59 -0
- package/include/mikrojs/errors.h +144 -0
- package/include/mikrojs/mem.h +11 -0
- package/include/mikrojs/mik_color.h +32 -0
- package/include/mikrojs/mikrojs.h +331 -0
- package/include/mikrojs/platform.h +82 -0
- package/include/mikrojs/private.h +281 -0
- package/include/mikrojs/utils.h +125 -0
- package/package.json +100 -0
- 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/ble/ble.ts +231 -0
- package/runtime/ble/types.ts +194 -0
- package/runtime/ble/uuid.ts +89 -0
- package/runtime/ble/validators.ts +61 -0
- package/runtime/cbor/cbor.ts +1 -0
- package/runtime/cbor/types.ts +8 -0
- package/runtime/console/types.ts +50 -0
- package/runtime/env/env.ts +17 -0
- package/runtime/env/types.ts +12 -0
- package/runtime/format/types.ts +4 -0
- package/runtime/fs/fs.ts +93 -0
- package/runtime/fs/types.ts +92 -0
- package/runtime/globals.d.ts +87 -0
- package/runtime/http/helpers.ts +222 -0
- package/runtime/http/native.ts +151 -0
- package/runtime/http/request.ts +25 -0
- package/runtime/i2c/i2c.ts +35 -0
- package/runtime/i2c/types.ts +55 -0
- package/runtime/inspect/types.ts +10 -0
- package/runtime/internal.d.ts +456 -0
- package/runtime/kv/nvs.ts +17 -0
- package/runtime/kv/rtc.ts +17 -0
- package/runtime/kv/shared.ts +107 -0
- package/runtime/kv/types.ts +150 -0
- package/runtime/neopixel/neopixel.ts +38 -0
- package/runtime/neopixel/types.ts +27 -0
- package/runtime/pin/pin.ts +51 -0
- package/runtime/pin/types.ts +49 -0
- package/runtime/pwm/pwm.ts +32 -0
- package/runtime/pwm/types.ts +29 -0
- package/runtime/reader/reader.ts +167 -0
- package/runtime/reader/types.ts +34 -0
- package/runtime/result/native-result.node-shim.ts +44 -0
- package/runtime/result/result.ts +26 -0
- package/runtime/result/types.ts +60 -0
- package/runtime/schema/schema.ts +321 -0
- package/runtime/schema/types.ts +152 -0
- package/runtime/sleep/sleep.ts +14 -0
- package/runtime/sleep/types.ts +44 -0
- package/runtime/sntp/sntp.ts +54 -0
- package/runtime/sntp/types.ts +38 -0
- package/runtime/spi/spi.ts +31 -0
- package/runtime/spi/types.ts +42 -0
- package/runtime/stdio/stdio.ts +44 -0
- package/runtime/stdio/types.ts +22 -0
- package/runtime/stream/stream.ts +150 -0
- package/runtime/stream/types.ts +47 -0
- package/runtime/sys/sys.ts +90 -0
- package/runtime/sys/types.ts +131 -0
- package/runtime/test/test.ts +595 -0
- package/runtime/test/types.ts +97 -0
- package/runtime/uart/types.ts +75 -0
- package/runtime/uart/uart.ts +51 -0
- package/runtime/wifi/types.ts +156 -0
- package/runtime/wifi/wifi.ts +208 -0
- package/scripts/bundle-runtime.js +149 -0
- package/scripts/compare-minifiers.js +189 -0
- package/scripts/compile-bytecode.sh +38 -0
- package/scripts/copy-prebuild.js +20 -0
- package/scripts/generate-symbol-map.js +146 -0
- package/src/builtins.cpp +82 -0
- package/src/cutils_compat.c +38 -0
- package/src/eval_bytecode.cpp +42 -0
- package/src/fs.cpp +878 -0
- package/src/mem.cpp +63 -0
- package/src/mik_abort.cpp +160 -0
- package/src/mik_app_config.cpp +358 -0
- package/src/mik_cbor.cpp +334 -0
- package/src/mik_color.cpp +46 -0
- package/src/mik_console.cpp +422 -0
- package/src/mik_inspect.cpp +850 -0
- package/src/mik_repl.cpp +1122 -0
- package/src/mik_result.cpp +344 -0
- package/src/mik_stdio.cpp +147 -0
- package/src/mik_sys.cpp +239 -0
- package/src/mik_text_encoding.cpp +443 -0
- package/src/mikrojs.cpp +942 -0
- package/src/modules.cpp +944 -0
- package/src/platform_posix.cpp +134 -0
- package/src/timers.cpp +208 -0
- package/src/utils.cpp +173 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#include <cstdarg>
|
|
2
|
+
#include <cstdio>
|
|
3
|
+
|
|
4
|
+
#include <quickjs.h>
|
|
5
|
+
|
|
6
|
+
#include "mikrojs/private.h"
|
|
7
|
+
#include "mikrojs/utils.h"
|
|
8
|
+
|
|
9
|
+
/* ── Result module ──────────────────────────────────────────────────
|
|
10
|
+
*
|
|
11
|
+
* Native implementation of the Result<T, E> abstraction. The public JS
|
|
12
|
+
* shape is unchanged: {ok: true, value} or {ok: false, error}. What's new
|
|
13
|
+
* is that every such object is allocated against a runtime-shared prototype
|
|
14
|
+
* holding the chaining methods (.map, .mapErr, .andThen, .match, .orDefault,
|
|
15
|
+
* .orPanic) + Symbol.for('mikrojs.inspect').
|
|
16
|
+
*
|
|
17
|
+
* Motivation: the previous TS implementation (runtime/result/result.ts)
|
|
18
|
+
* compiled to ~7 KB of per-runtime JS heap because every public runtime
|
|
19
|
+
* module (mikrojs/pin, mikrojs/wifi, …) top-level-imported it, so both
|
|
20
|
+
* OkImpl/ErrImpl class bodies and their ~16 method closures were paid once
|
|
21
|
+
* per runtime whether the app used them or not. Moving the prototype to C
|
|
22
|
+
* keeps the fluent API while collapsing that to a single shared proto +
|
|
23
|
+
* seven JSCFunction entries, most of which live in flash.
|
|
24
|
+
*
|
|
25
|
+
* All six methods branch on `this.ok` rather than living on two prototypes.
|
|
26
|
+
* The single-proto shape is what lets mik__result_ok/mik__result_err (used
|
|
27
|
+
* by every native module return value) stay a one-liner.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
static inline JSValue get_result_proto(JSContext* ctx) {
|
|
31
|
+
MIKRuntime* rt = MIK_GetRuntime(ctx);
|
|
32
|
+
if (!rt) return JS_NULL;
|
|
33
|
+
return rt->result_proto;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static inline JSValue new_result_obj(JSContext* ctx) {
|
|
37
|
+
JSValue proto = get_result_proto(ctx);
|
|
38
|
+
if (JS_IsNull(proto) || JS_IsUndefined(proto)) {
|
|
39
|
+
/* Fallback for the brief window before mik__result_init has run.
|
|
40
|
+
* Shouldn't happen in practice because the module is inited eagerly
|
|
41
|
+
* at the top of MIK_NewRuntimeInternal. */
|
|
42
|
+
return JS_NewObject(ctx);
|
|
43
|
+
}
|
|
44
|
+
return JS_NewObjectProto(ctx, proto);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
JSValue mik__result_ok(JSContext* ctx, JSValue value) {
|
|
48
|
+
JSValue obj = new_result_obj(ctx);
|
|
49
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_TRUE, JS_PROP_C_W_E);
|
|
50
|
+
JS_DefinePropertyValueStr(ctx, obj, "value", value, JS_PROP_C_W_E);
|
|
51
|
+
return obj;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
JSValue mik__result_ok_void(JSContext* ctx) {
|
|
55
|
+
MIKRuntime* rt = MIK_GetRuntime(ctx);
|
|
56
|
+
if (rt && !JS_IsUndefined(rt->result_ok_void_singleton)) {
|
|
57
|
+
return JS_DupValue(ctx, rt->result_ok_void_singleton);
|
|
58
|
+
}
|
|
59
|
+
/* Fallback for the brief window before mik__result_init has run. */
|
|
60
|
+
JSValue obj = new_result_obj(ctx);
|
|
61
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_TRUE, JS_PROP_C_W_E);
|
|
62
|
+
return obj;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
JSValue mik__result_err(JSContext* ctx, int code, int platform_errno, const char* fmt, ...) {
|
|
66
|
+
va_list ap;
|
|
67
|
+
va_start(ap, fmt);
|
|
68
|
+
char msg[256];
|
|
69
|
+
vsnprintf(msg, sizeof(msg), fmt, ap);
|
|
70
|
+
va_end(ap);
|
|
71
|
+
|
|
72
|
+
JSValue error = JS_NewObject(ctx);
|
|
73
|
+
JS_DefinePropertyValueStr(ctx, error, "code", JS_NewInt32(ctx, code), JS_PROP_C_W_E);
|
|
74
|
+
JS_DefinePropertyValueStr(ctx, error, "message", JS_NewString(ctx, msg), JS_PROP_C_W_E);
|
|
75
|
+
if (platform_errno) {
|
|
76
|
+
JS_DefinePropertyValueStr(ctx, error, "errno", JS_NewInt32(ctx, platform_errno),
|
|
77
|
+
JS_PROP_C_W_E);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
JSValue obj = new_result_obj(ctx);
|
|
81
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
82
|
+
JS_DefinePropertyValueStr(ctx, obj, "error", error, JS_PROP_C_W_E);
|
|
83
|
+
return obj;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
JSValue mik__result_err_named(JSContext* ctx, const char* name, const char* fmt, ...) {
|
|
87
|
+
va_list ap;
|
|
88
|
+
va_start(ap, fmt);
|
|
89
|
+
char msg[256];
|
|
90
|
+
vsnprintf(msg, sizeof(msg), fmt, ap);
|
|
91
|
+
va_end(ap);
|
|
92
|
+
|
|
93
|
+
JSValue error = JS_NewObject(ctx);
|
|
94
|
+
JS_DefinePropertyValueStr(ctx, error, "name", JS_NewString(ctx, name), JS_PROP_C_W_E);
|
|
95
|
+
JS_DefinePropertyValueStr(ctx, error, "message", JS_NewString(ctx, msg), JS_PROP_C_W_E);
|
|
96
|
+
|
|
97
|
+
JSValue obj = new_result_obj(ctx);
|
|
98
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
99
|
+
JS_DefinePropertyValueStr(ctx, obj, "error", error, JS_PROP_C_W_E);
|
|
100
|
+
return obj;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
JSValue mik__result_err_tag(JSContext* ctx, const char* name) {
|
|
104
|
+
JSValue error = JS_NewObject(ctx);
|
|
105
|
+
JS_DefinePropertyValueStr(ctx, error, "name", JS_NewString(ctx, name), JS_PROP_C_W_E);
|
|
106
|
+
|
|
107
|
+
JSValue obj = new_result_obj(ctx);
|
|
108
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
109
|
+
JS_DefinePropertyValueStr(ctx, obj, "error", error, JS_PROP_C_W_E);
|
|
110
|
+
return obj;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
JSValue mik__result_err_obj(JSContext* ctx, JSValue error_obj) {
|
|
114
|
+
JSValue obj = new_result_obj(ctx);
|
|
115
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
116
|
+
JS_DefinePropertyValueStr(ctx, obj, "error", error_obj, JS_PROP_C_W_E);
|
|
117
|
+
return obj;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ── Factory functions exported as `ok` / `err` ─────────────────── */
|
|
121
|
+
|
|
122
|
+
static JSValue js_result_ok(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
123
|
+
if (argc == 0) {
|
|
124
|
+
return mik__result_ok_void(ctx);
|
|
125
|
+
}
|
|
126
|
+
return mik__result_ok(ctx, JS_DupValue(ctx, argv[0]));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static JSValue js_result_err(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
130
|
+
JSValue obj = new_result_obj(ctx);
|
|
131
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
132
|
+
JS_DefinePropertyValueStr(ctx, obj, "error",
|
|
133
|
+
argc > 0 ? JS_DupValue(ctx, argv[0]) : JS_UNDEFINED,
|
|
134
|
+
JS_PROP_C_W_E);
|
|
135
|
+
return obj;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* ── Prototype method helpers ───────────────────────────────────── */
|
|
139
|
+
|
|
140
|
+
static inline bool result_is_ok(JSContext* ctx, JSValue this_val) {
|
|
141
|
+
JSValue ok_val = JS_GetPropertyStr(ctx, this_val, "ok");
|
|
142
|
+
bool is_ok = JS_ToBool(ctx, ok_val) != 0;
|
|
143
|
+
JS_FreeValue(ctx, ok_val);
|
|
144
|
+
return is_ok;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static JSValue result_get_value(JSContext* ctx, JSValue this_val) {
|
|
148
|
+
return JS_GetPropertyStr(ctx, this_val, "value");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static JSValue result_get_error(JSContext* ctx, JSValue this_val) {
|
|
152
|
+
return JS_GetPropertyStr(ctx, this_val, "error");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ── Prototype methods ──────────────────────────────────────────── */
|
|
156
|
+
|
|
157
|
+
/* .map(fn) — apply fn to value if ok, else pass through */
|
|
158
|
+
static JSValue js_result_map(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
159
|
+
if (!result_is_ok(ctx, this_val)) {
|
|
160
|
+
return JS_DupValue(ctx, this_val);
|
|
161
|
+
}
|
|
162
|
+
if (argc < 1 || !JS_IsFunction(ctx, argv[0])) {
|
|
163
|
+
return JS_ThrowTypeError(ctx, "Result.map: expected a function");
|
|
164
|
+
}
|
|
165
|
+
JSValue value = result_get_value(ctx, this_val);
|
|
166
|
+
JSValue mapped = JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &value);
|
|
167
|
+
JS_FreeValue(ctx, value);
|
|
168
|
+
if (JS_IsException(mapped)) return JS_EXCEPTION;
|
|
169
|
+
return mik__result_ok(ctx, mapped);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* .mapErr(fn) — apply fn to error if err, else pass through */
|
|
173
|
+
static JSValue js_result_map_err(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
174
|
+
if (result_is_ok(ctx, this_val)) {
|
|
175
|
+
return JS_DupValue(ctx, this_val);
|
|
176
|
+
}
|
|
177
|
+
if (argc < 1 || !JS_IsFunction(ctx, argv[0])) {
|
|
178
|
+
return JS_ThrowTypeError(ctx, "Result.mapErr: expected a function");
|
|
179
|
+
}
|
|
180
|
+
JSValue error = result_get_error(ctx, this_val);
|
|
181
|
+
JSValue mapped = JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &error);
|
|
182
|
+
JS_FreeValue(ctx, error);
|
|
183
|
+
if (JS_IsException(mapped)) return JS_EXCEPTION;
|
|
184
|
+
JSValue obj = new_result_obj(ctx);
|
|
185
|
+
JS_DefinePropertyValueStr(ctx, obj, "ok", JS_FALSE, JS_PROP_C_W_E);
|
|
186
|
+
JS_DefinePropertyValueStr(ctx, obj, "error", mapped, JS_PROP_C_W_E);
|
|
187
|
+
return obj;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* .andThen(fn) — if ok, call fn(value) and return its result; else pass through */
|
|
191
|
+
static JSValue js_result_and_then(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
192
|
+
if (!result_is_ok(ctx, this_val)) {
|
|
193
|
+
return JS_DupValue(ctx, this_val);
|
|
194
|
+
}
|
|
195
|
+
if (argc < 1 || !JS_IsFunction(ctx, argv[0])) {
|
|
196
|
+
return JS_ThrowTypeError(ctx, "Result.andThen: expected a function");
|
|
197
|
+
}
|
|
198
|
+
JSValue value = result_get_value(ctx, this_val);
|
|
199
|
+
JSValue next = JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &value);
|
|
200
|
+
JS_FreeValue(ctx, value);
|
|
201
|
+
return next;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* .match({ok, err}) — dispatch to the appropriate handler */
|
|
205
|
+
static JSValue js_result_match(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
206
|
+
if (argc < 1 || !JS_IsObject(argv[0])) {
|
|
207
|
+
return JS_ThrowTypeError(ctx, "Result.match: expected {ok, err} handlers");
|
|
208
|
+
}
|
|
209
|
+
const char* key = result_is_ok(ctx, this_val) ? "ok" : "err";
|
|
210
|
+
JSValue handler = JS_GetPropertyStr(ctx, argv[0], key);
|
|
211
|
+
if (!JS_IsFunction(ctx, handler)) {
|
|
212
|
+
JS_FreeValue(ctx, handler);
|
|
213
|
+
return JS_ThrowTypeError(ctx, "Result.match: missing '%s' handler", key);
|
|
214
|
+
}
|
|
215
|
+
JSValue payload =
|
|
216
|
+
result_is_ok(ctx, this_val) ? result_get_value(ctx, this_val) : result_get_error(ctx, this_val);
|
|
217
|
+
JSValue ret = JS_Call(ctx, handler, JS_UNDEFINED, 1, &payload);
|
|
218
|
+
JS_FreeValue(ctx, payload);
|
|
219
|
+
JS_FreeValue(ctx, handler);
|
|
220
|
+
return ret;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* .orDefault(d) — value if ok, else d */
|
|
224
|
+
static JSValue js_result_or_default(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
225
|
+
if (result_is_ok(ctx, this_val)) {
|
|
226
|
+
return result_get_value(ctx, this_val);
|
|
227
|
+
}
|
|
228
|
+
return argc > 0 ? JS_DupValue(ctx, argv[0]) : JS_UNDEFINED;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* .orPanic(msg) — value if ok, else throw an Error(name=PanicError, cause=error) */
|
|
232
|
+
static JSValue js_result_or_panic(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
233
|
+
if (result_is_ok(ctx, this_val)) {
|
|
234
|
+
return result_get_value(ctx, this_val);
|
|
235
|
+
}
|
|
236
|
+
JSValue panic = JS_NewError(ctx);
|
|
237
|
+
const char* msg = NULL;
|
|
238
|
+
if (argc > 0) {
|
|
239
|
+
msg = JS_ToCString(ctx, argv[0]);
|
|
240
|
+
}
|
|
241
|
+
JS_DefinePropertyValueStr(ctx, panic, "message",
|
|
242
|
+
JS_NewString(ctx, msg ? msg : "panic"),
|
|
243
|
+
JS_PROP_C_W_E);
|
|
244
|
+
if (msg) JS_FreeCString(ctx, msg);
|
|
245
|
+
JS_DefinePropertyValueStr(ctx, panic, "name", JS_NewString(ctx, "PanicError"),
|
|
246
|
+
JS_PROP_C_W_E);
|
|
247
|
+
JSValue cause = result_get_error(ctx, this_val);
|
|
248
|
+
JS_DefinePropertyValueStr(ctx, panic, "cause", cause, JS_PROP_C_W_E);
|
|
249
|
+
return JS_Throw(ctx, panic);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Symbol.for('mikrojs.inspect')(depth, inspect) — matches the TS output
|
|
253
|
+
* ("Ok<value>" / "Err<error>") so console.log stays unchanged. */
|
|
254
|
+
static JSValue js_result_inspect(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
255
|
+
if (argc < 2 || !JS_IsFunction(ctx, argv[1])) {
|
|
256
|
+
return JS_NewString(ctx, result_is_ok(ctx, this_val) ? "Ok<?>" : "Err<?>");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
bool is_ok = result_is_ok(ctx, this_val);
|
|
260
|
+
JSValue inner =
|
|
261
|
+
is_ok ? result_get_value(ctx, this_val) : result_get_error(ctx, this_val);
|
|
262
|
+
JSValue inner_str = JS_Call(ctx, argv[1], JS_UNDEFINED, 1, &inner);
|
|
263
|
+
JS_FreeValue(ctx, inner);
|
|
264
|
+
if (JS_IsException(inner_str)) return JS_EXCEPTION;
|
|
265
|
+
|
|
266
|
+
const char* s = JS_ToCString(ctx, inner_str);
|
|
267
|
+
JS_FreeValue(ctx, inner_str);
|
|
268
|
+
if (!s) return JS_EXCEPTION;
|
|
269
|
+
|
|
270
|
+
char buf[256];
|
|
271
|
+
snprintf(buf, sizeof(buf), "%s<%s>", is_ok ? "Ok" : "Err", s);
|
|
272
|
+
JS_FreeCString(ctx, s);
|
|
273
|
+
return JS_NewString(ctx, buf);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* ── Prototype assembly ─────────────────────────────────────────── */
|
|
277
|
+
|
|
278
|
+
static void mik__result_install_methods(JSContext* ctx, JSValue proto) {
|
|
279
|
+
struct {
|
|
280
|
+
const char* name;
|
|
281
|
+
JSCFunction* fn;
|
|
282
|
+
int length;
|
|
283
|
+
} methods[] = {
|
|
284
|
+
{"map", js_result_map, 1}, {"mapErr", js_result_map_err, 1},
|
|
285
|
+
{"andThen", js_result_and_then, 1}, {"match", js_result_match, 1},
|
|
286
|
+
{"orDefault", js_result_or_default, 1}, {"orPanic", js_result_or_panic, 1},
|
|
287
|
+
};
|
|
288
|
+
for (const auto& m : methods) {
|
|
289
|
+
JS_DefinePropertyValueStr(ctx, proto, m.name,
|
|
290
|
+
JS_NewCFunction(ctx, m.fn, m.name, m.length),
|
|
291
|
+
JS_PROP_C_W_E);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* Symbol.for('mikrojs.inspect') */
|
|
295
|
+
JSValue global = JS_GetGlobalObject(ctx);
|
|
296
|
+
JSValue symbol_ctor = JS_GetPropertyStr(ctx, global, "Symbol");
|
|
297
|
+
JS_FreeValue(ctx, global);
|
|
298
|
+
JSValue symbol_for = JS_GetPropertyStr(ctx, symbol_ctor, "for");
|
|
299
|
+
JS_FreeValue(ctx, symbol_ctor);
|
|
300
|
+
JSValue key_str = JS_NewString(ctx, "mikrojs.inspect");
|
|
301
|
+
JSValue inspect_sym = JS_Call(ctx, symbol_for, JS_UNDEFINED, 1, &key_str);
|
|
302
|
+
JS_FreeValue(ctx, key_str);
|
|
303
|
+
JS_FreeValue(ctx, symbol_for);
|
|
304
|
+
if (!JS_IsException(inspect_sym)) {
|
|
305
|
+
JSAtom atom = JS_ValueToAtom(ctx, inspect_sym);
|
|
306
|
+
JS_FreeValue(ctx, inspect_sym);
|
|
307
|
+
JS_DefinePropertyValue(
|
|
308
|
+
ctx, proto, atom,
|
|
309
|
+
JS_NewCFunction(ctx, js_result_inspect, "[mikrojs.inspect]", 2),
|
|
310
|
+
JS_PROP_C_W_E);
|
|
311
|
+
JS_FreeAtom(ctx, atom);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* ── Module init ────────────────────────────────────────────────── */
|
|
316
|
+
|
|
317
|
+
static int mik__result_module_init(JSContext* ctx, JSModuleDef* m) {
|
|
318
|
+
JS_SetModuleExport(ctx, m, "ok", JS_NewCFunction(ctx, js_result_ok, "ok", 1));
|
|
319
|
+
JS_SetModuleExport(ctx, m, "err", JS_NewCFunction(ctx, js_result_err, "err", 1));
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
JSModuleDef* mik__result_init(JSContext* ctx) {
|
|
324
|
+
MIKRuntime* rt = MIK_GetRuntime(ctx);
|
|
325
|
+
if (rt && JS_IsUndefined(rt->result_proto)) {
|
|
326
|
+
JSValue proto = JS_NewObject(ctx);
|
|
327
|
+
mik__result_install_methods(ctx, proto);
|
|
328
|
+
rt->result_proto = proto;
|
|
329
|
+
|
|
330
|
+
/* Build the frozen {ok: true} singleton used by every mik__result_ok_void
|
|
331
|
+
* call. Freezing makes mutation throw in strict mode and blocks added
|
|
332
|
+
* properties, so a single shared instance is safe. */
|
|
333
|
+
JSValue singleton = JS_NewObjectProto(ctx, proto);
|
|
334
|
+
JS_DefinePropertyValueStr(ctx, singleton, "ok", JS_TRUE, JS_PROP_C_W_E);
|
|
335
|
+
JS_FreezeObject(ctx, singleton);
|
|
336
|
+
rt->result_ok_void_singleton = singleton;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
JSModuleDef* m = JS_NewCModule(ctx, "native:result", mik__result_module_init);
|
|
340
|
+
if (!m) return nullptr;
|
|
341
|
+
JS_AddModuleExport(ctx, m, "ok");
|
|
342
|
+
JS_AddModuleExport(ctx, m, "err");
|
|
343
|
+
return m;
|
|
344
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#include <quickjs.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include <unistd.h>
|
|
5
|
+
|
|
6
|
+
#include "mikrojs/platform.h"
|
|
7
|
+
#include "mikrojs/private.h"
|
|
8
|
+
#include "mikrojs/utils.h"
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Non-blocking read from stdin via VFS.
|
|
12
|
+
* Works with any ESP-IDF console backend (UART, USB Serial/JTAG, etc.)
|
|
13
|
+
* The default VFS console driver is already non-blocking for reads.
|
|
14
|
+
*/
|
|
15
|
+
static int mik__stdin_read_raw(uint8_t* buf, size_t size) {
|
|
16
|
+
return MIK_GetPlatform()->stdin_read(buf, size);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static JSValue mik__stdout_write(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
20
|
+
if (mik__repl_is_protocol_mode()) {
|
|
21
|
+
if (JS_GetTypedArrayType(argv[0]) == JS_TYPED_ARRAY_UINT8) {
|
|
22
|
+
size_t size;
|
|
23
|
+
const uint8_t* buf = JS_GetUint8Array(ctx, &size, argv[0]);
|
|
24
|
+
if (!buf) return JS_EXCEPTION;
|
|
25
|
+
mik__repl_proto_send_output(MIK_MSG_LOG, buf, size);
|
|
26
|
+
} else {
|
|
27
|
+
const char* str = JS_ToCString(ctx, argv[0]);
|
|
28
|
+
if (!str) return JS_EXCEPTION;
|
|
29
|
+
mik__repl_proto_send_output(MIK_MSG_LOG, str, strlen(str));
|
|
30
|
+
JS_FreeCString(ctx, str);
|
|
31
|
+
}
|
|
32
|
+
return JS_UNDEFINED;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (JS_GetTypedArrayType(argv[0]) == JS_TYPED_ARRAY_UINT8) {
|
|
36
|
+
size_t size;
|
|
37
|
+
const uint8_t* buf = JS_GetUint8Array(ctx, &size, argv[0]);
|
|
38
|
+
if (!buf) {
|
|
39
|
+
return JS_EXCEPTION;
|
|
40
|
+
}
|
|
41
|
+
MIK_GetPlatform()->stdout_write(buf, size);
|
|
42
|
+
} else {
|
|
43
|
+
const char* str = JS_ToCString(ctx, argv[0]);
|
|
44
|
+
if (!str) {
|
|
45
|
+
return JS_EXCEPTION;
|
|
46
|
+
}
|
|
47
|
+
MIK_GetPlatform()->stdout_write(str, strlen(str));
|
|
48
|
+
JS_FreeCString(ctx, str);
|
|
49
|
+
}
|
|
50
|
+
return JS_UNDEFINED;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static JSValue mik__stdout_flush(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
54
|
+
fflush(stdout);
|
|
55
|
+
fsync(fileno(stdout));
|
|
56
|
+
return JS_UNDEFINED;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static JSValue mik__stdin_read_js(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
60
|
+
uint8_t buf[MIK_STDIN_BUF_SIZE];
|
|
61
|
+
int len = mik__stdin_read_raw(buf, sizeof(buf));
|
|
62
|
+
|
|
63
|
+
if (len <= 0) {
|
|
64
|
+
return JS_UNDEFINED;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return JS_NewUint8ArrayCopy(ctx, buf, len);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* Register a JS callback to receive stdin data.
|
|
72
|
+
* Called from the event loop (mik__stdin_consume) — no timers needed.
|
|
73
|
+
*/
|
|
74
|
+
static JSValue mik__stdin_set_handler(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
75
|
+
MIKRuntime* mik_rt = MIK_GetRuntime(ctx);
|
|
76
|
+
CHECK_NOT_NULL(mik_rt);
|
|
77
|
+
|
|
78
|
+
if (!JS_IsFunction(ctx, argv[0])) {
|
|
79
|
+
return JS_ThrowTypeError(ctx, "expected a function");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Free previous handler if set */
|
|
83
|
+
if (!JS_IsUndefined(mik_rt->stdin_state.on_data)) {
|
|
84
|
+
JS_FreeValue(ctx, mik_rt->stdin_state.on_data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
mik_rt->stdin_state.on_data = JS_DupValue(ctx, argv[0]);
|
|
88
|
+
return JS_UNDEFINED;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* Unregister the stdin data callback.
|
|
93
|
+
*/
|
|
94
|
+
static JSValue mik__stdin_clear_handler(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
|
|
95
|
+
MIKRuntime* mik_rt = MIK_GetRuntime(ctx);
|
|
96
|
+
CHECK_NOT_NULL(mik_rt);
|
|
97
|
+
|
|
98
|
+
if (!JS_IsUndefined(mik_rt->stdin_state.on_data)) {
|
|
99
|
+
JS_FreeValue(ctx, mik_rt->stdin_state.on_data);
|
|
100
|
+
mik_rt->stdin_state.on_data = JS_UNDEFINED;
|
|
101
|
+
}
|
|
102
|
+
return JS_UNDEFINED;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* Called from MIK_Loop — reads stdin and dispatches to the JS handler.
|
|
107
|
+
*/
|
|
108
|
+
void mik__stdin_consume(JSContext* ctx) {
|
|
109
|
+
MIKRuntime* mik_rt = MIK_GetRuntime(ctx);
|
|
110
|
+
CHECK_NOT_NULL(mik_rt);
|
|
111
|
+
|
|
112
|
+
if (JS_IsUndefined(mik_rt->stdin_state.on_data)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
uint8_t buf[256];
|
|
117
|
+
int len = mik__stdin_read_raw(buf, sizeof(buf));
|
|
118
|
+
if (len <= 0) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
JSValue data = JS_NewUint8ArrayCopy(ctx, buf, len);
|
|
123
|
+
JSValue ret = JS_Call(ctx, mik_rt->stdin_state.on_data, JS_UNDEFINED, 1, &data);
|
|
124
|
+
JS_FreeValue(ctx, data);
|
|
125
|
+
if (JS_IsException(ret)) {
|
|
126
|
+
mik_dump_error(ctx);
|
|
127
|
+
}
|
|
128
|
+
JS_FreeValue(ctx, ret);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
void mik__stdio_init(JSContext* ctx, JSValue ns) {
|
|
132
|
+
/* stdout */
|
|
133
|
+
JSValue p_stdout = JS_NewObject(ctx);
|
|
134
|
+
JS_SetPropertyStr(ctx, p_stdout, "write", JS_NewCFunction(ctx, mik__stdout_write, "write", 1));
|
|
135
|
+
JS_SetPropertyStr(ctx, p_stdout, "flush",
|
|
136
|
+
JS_NewCFunction(ctx, mik__stdout_flush, "flush", 0));
|
|
137
|
+
JS_SetPropertyStr(ctx, ns, "stdout", p_stdout);
|
|
138
|
+
|
|
139
|
+
/* stdin */
|
|
140
|
+
JSValue p_stdin = JS_NewObject(ctx);
|
|
141
|
+
JS_SetPropertyStr(ctx, p_stdin, "read", JS_NewCFunction(ctx, mik__stdin_read_js, "read", 0));
|
|
142
|
+
JS_SetPropertyStr(ctx, p_stdin, "setHandler",
|
|
143
|
+
JS_NewCFunction(ctx, mik__stdin_set_handler, "setHandler", 1));
|
|
144
|
+
JS_SetPropertyStr(ctx, p_stdin, "clearHandler",
|
|
145
|
+
JS_NewCFunction(ctx, mik__stdin_clear_handler, "clearHandler", 0));
|
|
146
|
+
JS_SetPropertyStr(ctx, ns, "stdin", p_stdin);
|
|
147
|
+
}
|