/
mjs_core_public.h
234 lines (207 loc) · 6.23 KB
/
mjs_core_public.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*
* Copyright (c) 2016 Cesanta Software Limited
* All rights reserved
*/
#ifndef MJS_CORE_PUBLIC_H_
#define MJS_CORE_PUBLIC_H_
#if !defined(_MSC_VER) || _MSC_VER >= 1700
#include <stdint.h>
#else
typedef unsigned __int64 uint64_t;
typedef int int32_t;
typedef unsigned char uint8_t;
#endif
#include <stdio.h>
#include <stddef.h>
#include "mjs_features.h"
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
#ifndef MJS_ENABLE_DEBUG
#define MJS_ENABLE_DEBUG 0
#endif
/*
* Double-precision floating-point number, IEEE 754
*
* 64 bit (8 bytes) in total
* 1 bit sign
* 11 bits exponent
* 52 bits mantissa
* 7 6 5 4 3 2 1 0
* seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm
*
* If an exponent is all-1 and mantissa is all-0, then it is an INFINITY:
* 11111111|11110000|00000000|00000000|00000000|00000000|00000000|00000000
*
* If an exponent is all-1 and mantissa's MSB is 1, it is a quiet NaN:
* 11111111|11111000|00000000|00000000|00000000|00000000|00000000|00000000
*
* MJS NaN-packing:
* sign and exponent is 0xfff
* 4 bits specify type (tag), must be non-zero
* 48 bits specify value
*
* 11111111|1111tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv
* NaN marker |type| 48-bit placeholder for values: pointers, strings
*
* On 64-bit platforms, pointers are really 48 bit only, so they can fit,
* provided they are sign extended
*/
typedef uint64_t mjs_val_t;
/* This if-0 is a dirty workaround to force etags to pick `struct mjs` */
#if 0
/* Opaque structure. MJS engine context. */
struct mjs {
/* ... */
};
#endif
struct mjs;
typedef enum mjs_err {
MJS_OK,
MJS_SYNTAX_ERROR,
MJS_REFERENCE_ERROR,
MJS_TYPE_ERROR,
MJS_OUT_OF_MEMORY,
MJS_INTERNAL_ERROR,
MJS_NOT_IMPLEMENTED_ERROR,
MJS_FILE_READ_ERROR,
MJS_BAD_ARGS_ERROR,
MJS_ERRS_CNT
} mjs_err_t;
struct mjs;
/* Create MJS instance */
struct mjs *mjs_create();
struct mjs_create_opts {
/* use non-default bytecode definition file, testing-only */
const struct bf_code *code;
};
/*
* Like `msj_create()`, but allows to customize initial MJS state, see `struct
* mjs_create_opts`.
*/
struct mjs *mjs_create_opt(struct mjs_create_opts opts);
/* Destroy MJS instance */
void mjs_destroy(struct mjs *mjs);
mjs_val_t mjs_get_global(struct mjs *mjs);
/*
* Tells the GC about an MJS value variable/field owned by C code.
*
* The user's C code should own mjs_val_t variables if the value's lifetime
* crosses any invocation of `mjs_exec()` and friends, including `mjs_call()`.
*
* The registration of the variable prevents the GC from mistakenly treat the
* object as garbage.
*
* User code should also explicitly disown the variables with `mjs_disown()`
* once it goes out of scope or the structure containing the mjs_val_t field is
* freed.
*
* Consider the following examples:
*
* Correct (owning is not necessary):
* ```c
* mjs_val_t res;
* mjs_exec(mjs, "....some script", &res);
* // ... use res somehow
*
* mjs_val_t res;
* mjs_exec(mjs, "....some script2", &res);
* // ... use new res somehow
* ```
*
* WRONG:
* ```c
* mjs_val_t res1;
* mjs_exec(mjs, "....some script", &res1);
*
* mjs_val_t res2;
* mjs_exec(mjs, "....some script2", &res2);
*
* // ... use res1 (WRONG!) and res2
* ```
*
* The code above is wrong, because after the second invocation of
* `mjs_exec()`, the value of `res1` is invalidated.
*
* Correct (res1 is owned)
* ```c
* mjs_val_t res1 = MJS_UNDEFINED;
* mjs_own(mjs, &res1);
* mjs_exec(mjs, "....some script", &res1);
*
* mjs_val_t res2 = MJS_UNDEFINED;
* mjs_exec(mjs, "....some script2", &res2);
*
* // ... use res1 and res2
* mjs_disown(mjs, &res1);
* ```
*
* NOTE that we explicly initialized `res1` to a valid value before owning it
* (in this case, the value is `MJS_UNDEFINED`). Owning an uninitialized
* variable is an undefined behaviour.
*
* Of course, it's not an error to own a variable even if it's not mandatory:
* e.g. in the last example we could own both `res1` and `res2`. Probably it
* would help us in the future, when we refactor the code so that `res2` has to
* be owned, and we could forget to do that.
*
* Also, if the user code has some C function called from MJS, and in this C
* function some MJS value (`mjs_val_t`) needs to be stored somewhere and to
* stay alive after the C function has returned, it also needs to be properly
* owned.
*/
void mjs_own(struct mjs *mjs, mjs_val_t *v);
/*
* Disowns the value previously owned by `mjs_own()`.
*
* Returns 1 if value is found, 0 otherwise.
*/
int mjs_disown(struct mjs *mjs, mjs_val_t *v);
mjs_err_t mjs_set_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...);
/*
* If there is no error message already set, then it's equal to
* `mjs_set_errorf()`.
*
* Otherwise, an old message gets prepended with the new one, followed by a
* colon. (the previously set error code is kept)
*/
mjs_err_t mjs_prepend_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt,
...);
/*
* Print the last error details. If print_stack_trace is non-zero, also
* print stack trace. `msg` is the message which gets prepended to the actual
* error message, if it's NULL, then "MJS error" is used.
*/
void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg,
int print_stack_trace);
/*
* return a string representation of an error.
* the error string might be overwritten by calls to `mjs_set_errorf`.
*/
const char *mjs_strerror(struct mjs *mjs, enum mjs_err err);
/*
* Sets whether *.jsc files are generated when *.js file is executed. By
* default it's 0.
*
* If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no
* effect.
*/
void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc);
/*
* When invoked from a cfunction, returns number of arguments passed to the
* current JS function call.
*/
int mjs_nargs(struct mjs *mjs);
/*
* When invoked from a cfunction, returns n-th argument to the current JS
* function call.
*/
mjs_val_t mjs_arg(struct mjs *mjs, int n);
/*
* Sets return value for the current JS function call.
*/
void mjs_return(struct mjs *mjs, mjs_val_t v);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* MJS_CORE_PUBLIC_H_ */