Flipper Zero Firmware
Loading...
Searching...
No Matches
mjs_core_public.h
1/*
2 * Copyright (c) 2016 Cesanta Software Limited
3 * All rights reserved
4 */
5
6#ifndef MJS_CORE_PUBLIC_H_
7#define MJS_CORE_PUBLIC_H_
8
9#if !defined(_MSC_VER) || _MSC_VER >= 1700
10#include <stdint.h>
11#else
12typedef unsigned __int64 uint64_t;
13typedef int int32_t;
14typedef unsigned char uint8_t;
15#endif
16#include <stdio.h>
17#include <stddef.h>
18#include "mjs_features.h"
19
20#if defined(__cplusplus)
21extern "C" {
22#endif /* __cplusplus */
23
24#ifndef MJS_ENABLE_DEBUG
25#define MJS_ENABLE_DEBUG 0
26#endif
27
28/*
29 * Double-precision floating-point number, IEEE 754
30 *
31 * 64 bit (8 bytes) in total
32 * 1 bit sign
33 * 11 bits exponent
34 * 52 bits mantissa
35 * 7 6 5 4 3 2 1 0
36 * seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm
37 *
38 * If an exponent is all-1 and mantissa is all-0, then it is an INFINITY:
39 * 11111111|11110000|00000000|00000000|00000000|00000000|00000000|00000000
40 *
41 * If an exponent is all-1 and mantissa's MSB is 1, it is a quiet NaN:
42 * 11111111|11111000|00000000|00000000|00000000|00000000|00000000|00000000
43 *
44 * MJS NaN-packing:
45 * sign and exponent is 0xfff
46 * 4 bits specify type (tag), must be non-zero
47 * 48 bits specify value
48 *
49 * 11111111|1111tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv
50 * NaN marker |type| 48-bit placeholder for values: pointers, strings
51 *
52 * On 64-bit platforms, pointers are really 48 bit only, so they can fit,
53 * provided they are sign extended
54 */
55
56typedef uint64_t mjs_val_t;
57
58/*
59 * A tag is made of the sign bit and the 4 lower order bits of byte 6.
60 * So in total we have 32 possible tags.
61 *
62 * Tag (1,0) however cannot hold a zero payload otherwise it's interpreted as an
63 * INFINITY; for simplicity we're just not going to use that combination.
64 */
65#define MAKE_TAG(s, t) ((uint64_t)(s) << 63 | (uint64_t)0x7ff0 << 48 | (uint64_t)(t) << 48)
66
67#define MJS_TAG_OBJECT MAKE_TAG(1, 1)
68#define MJS_TAG_FOREIGN MAKE_TAG(1, 2)
69#define MJS_TAG_UNDEFINED MAKE_TAG(1, 3)
70#define MJS_TAG_BOOLEAN MAKE_TAG(1, 4)
71#define MJS_TAG_NAN MAKE_TAG(1, 5)
72#define MJS_TAG_STRING_I MAKE_TAG(1, 6) /* Inlined string len < 5 */
73#define MJS_TAG_STRING_5 MAKE_TAG(1, 7) /* Inlined string len 5 */
74#define MJS_TAG_STRING_O MAKE_TAG(1, 8) /* Owned string */
75#define MJS_TAG_STRING_F MAKE_TAG(1, 9) /* Foreign string */
76#define MJS_TAG_STRING_C MAKE_TAG(1, 10) /* String chunk */
77#define MJS_TAG_STRING_D MAKE_TAG(1, 11) /* Dictionary string */
78#define MJS_TAG_ARRAY MAKE_TAG(1, 12)
79#define MJS_TAG_FUNCTION MAKE_TAG(1, 13)
80#define MJS_TAG_FUNCTION_FFI MAKE_TAG(1, 14)
81#define MJS_TAG_NULL MAKE_TAG(1, 15)
82
83#define MJS_TAG_ARRAY_BUF MAKE_TAG(0, 1) /* ArrayBuffer */
84#define MJS_TAG_ARRAY_BUF_VIEW MAKE_TAG(0, 2) /* DataView */
85
86#define MJS_TAG_MASK MAKE_TAG(1, 15)
87
88/* This if-0 is a dirty workaround to force etags to pick `struct mjs` */
89#if 0
90/* Opaque structure. MJS engine context. */
91struct mjs {
92 /* ... */
93};
94#endif
95
96struct mjs;
97
98enum mjs_type {
99 /* Primitive types */
100 MJS_TYPE_UNDEFINED,
101 MJS_TYPE_NULL,
102 MJS_TYPE_BOOLEAN,
103 MJS_TYPE_NUMBER,
104 MJS_TYPE_STRING,
105 MJS_TYPE_FOREIGN,
106 MJS_TYPE_ARRAY_BUF,
107 MJS_TYPE_ARRAY_BUF_VIEW,
108
109 /* Different classes of Object type */
110 MJS_TYPE_OBJECT_GENERIC,
111 MJS_TYPE_OBJECT_ARRAY,
112 MJS_TYPE_OBJECT_FUNCTION,
113 /*
114 * TODO(dfrank): if we support prototypes, need to add items for them here
115 */
116
117 MJS_TYPES_CNT
118};
119
120typedef enum mjs_err {
121 MJS_OK,
122 MJS_SYNTAX_ERROR,
123 MJS_REFERENCE_ERROR,
124 MJS_TYPE_ERROR,
125 MJS_OUT_OF_MEMORY,
126 MJS_INTERNAL_ERROR,
127 MJS_NOT_IMPLEMENTED_ERROR,
128 MJS_FILE_READ_ERROR,
129 MJS_BAD_ARGS_ERROR,
130
131 MJS_NEED_EXIT,
132
133 MJS_ERRS_CNT
134} mjs_err_t;
135
136typedef void (*mjs_flags_poller_t)(struct mjs* mjs);
137
138struct mjs;
139
140/* Create MJS instance */
141struct mjs* mjs_create(void* context);
142
143/* Destroy MJS instance */
144void mjs_destroy(struct mjs* mjs);
145
146mjs_val_t mjs_get_global(struct mjs* mjs);
147
148/*
149 * Tells the GC about an MJS value variable/field owned by C code.
150 *
151 * The user's C code should own mjs_val_t variables if the value's lifetime
152 * crosses any invocation of `mjs_exec()` and friends, including `mjs_call()`.
153 *
154 * The registration of the variable prevents the GC from mistakenly treat the
155 * object as garbage.
156 *
157 * User code should also explicitly disown the variables with `mjs_disown()`
158 * once it goes out of scope or the structure containing the mjs_val_t field is
159 * freed.
160 *
161 * Consider the following examples:
162 *
163 * Correct (owning is not necessary):
164 * ```c
165 * mjs_val_t res;
166 * mjs_exec(mjs, "....some script", &res);
167 * // ... use res somehow
168 *
169 * mjs_val_t res;
170 * mjs_exec(mjs, "....some script2", &res);
171 * // ... use new res somehow
172 * ```
173 *
174 * WRONG:
175 * ```c
176 * mjs_val_t res1;
177 * mjs_exec(mjs, "....some script", &res1);
178 *
179 * mjs_val_t res2;
180 * mjs_exec(mjs, "....some script2", &res2);
181 *
182 * // ... use res1 (WRONG!) and res2
183 * ```
184 *
185 * The code above is wrong, because after the second invocation of
186 * `mjs_exec()`, the value of `res1` is invalidated.
187 *
188 * Correct (res1 is owned)
189 * ```c
190 * mjs_val_t res1 = MJS_UNDEFINED;
191 * mjs_own(mjs, &res1);
192 * mjs_exec(mjs, "....some script", &res1);
193 *
194 * mjs_val_t res2 = MJS_UNDEFINED;
195 * mjs_exec(mjs, "....some script2", &res2);
196 *
197 * // ... use res1 and res2
198 * mjs_disown(mjs, &res1);
199 * ```
200 *
201 * NOTE that we explicly initialized `res1` to a valid value before owning it
202 * (in this case, the value is `MJS_UNDEFINED`). Owning an uninitialized
203 * variable is an undefined behaviour.
204 *
205 * Of course, it's not an error to own a variable even if it's not mandatory:
206 * e.g. in the last example we could own both `res1` and `res2`. Probably it
207 * would help us in the future, when we refactor the code so that `res2` has to
208 * be owned, and we could forget to do that.
209 *
210 * Also, if the user code has some C function called from MJS, and in this C
211 * function some MJS value (`mjs_val_t`) needs to be stored somewhere and to
212 * stay alive after the C function has returned, it also needs to be properly
213 * owned.
214 */
215void mjs_own(struct mjs* mjs, mjs_val_t* v);
216
217/*
218 * Disowns the value previously owned by `mjs_own()`.
219 *
220 * Returns 1 if value is found, 0 otherwise.
221 */
222int mjs_disown(struct mjs* mjs, mjs_val_t* v);
223
224mjs_err_t mjs_set_errorf(struct mjs* mjs, mjs_err_t err, const char* fmt, ...);
225
226void mjs_exit(struct mjs* mjs);
227
228void mjs_set_exec_flags_poller(struct mjs* mjs, mjs_flags_poller_t poller);
229
230void* mjs_get_context(struct mjs* mjs);
231
232/*
233 * If there is no error message already set, then it's equal to
234 * `mjs_set_errorf()`.
235 *
236 * Otherwise, an old message gets prepended with the new one, followed by a
237 * colon. (the previously set error code is kept)
238 */
239mjs_err_t mjs_prepend_errorf(struct mjs* mjs, mjs_err_t err, const char* fmt, ...);
240
241/*
242 * Print the last error details. If print_stack_trace is non-zero, also
243 * print stack trace. `msg` is the message which gets prepended to the actual
244 * error message, if it's NULL, then "MJS error" is used.
245 */
246void mjs_print_error(struct mjs* mjs, FILE* fp, const char* msg, int print_stack_trace);
247
248/*
249 * return a string representation of an error.
250 * the error string might be overwritten by calls to `mjs_set_errorf`.
251 */
252const char* mjs_strerror(struct mjs* mjs, enum mjs_err err);
253
254const char* mjs_get_stack_trace(struct mjs* mjs);
255
256/*
257 * Sets whether *.jsc files are generated when *.js file is executed. By
258 * default it's 0.
259 *
260 * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no
261 * effect.
262 */
263void mjs_set_generate_jsc(struct mjs* mjs, int generate_jsc);
264
265/*
266 * When invoked from a cfunction, returns number of arguments passed to the
267 * current JS function call.
268 */
269int mjs_nargs(struct mjs* mjs);
270
271/*
272 * When invoked from a cfunction, returns n-th argument to the current JS
273 * function call.
274 */
275mjs_val_t mjs_arg(struct mjs* mjs, int n);
276
277/*
278 * Sets return value for the current JS function call.
279 */
280void mjs_return(struct mjs* mjs, mjs_val_t v);
281
282#if defined(__cplusplus)
283}
284#endif /* __cplusplus */
285
286#endif /* MJS_CORE_PUBLIC_H_ */
Definition mjs_core.h:63