Loading...
Searching...
No Matches
js_modules.h
1#pragma once
2
3#include <stdint.h>
4#include "js_thread_i.h"
6#include <flipper_application/plugins/plugin_manager.h>
7#include <flipper_application/plugins/composite_resolver.h>
8
9#define PLUGIN_APP_ID "js"
10#define PLUGIN_API_VERSION 1
11
12#define JS_SDK_VENDOR "flipperdevices"
13#define JS_SDK_MAJOR 0
14#define JS_SDK_MINOR 1
15
19#define JS_GET_INST(mjs, obj) mjs_get_ptr(mjs, mjs_get(mjs, obj, INST_PROP_NAME, ~0))
23#define JS_GET_CONTEXT(mjs) JS_GET_INST(mjs, mjs_get_this(mjs))
24
37#define JS_ASSIGN_MULTI(mjs, object) \
38 for(struct { \
39 struct mjs* mjs; \
40 mjs_val_t val; \
41 int i; \
42 } _ass_multi = {mjs, object, 0}; \
43 _ass_multi.i == 0; \
44 _ass_multi.i++)
45#define JS_FIELD(name, value) mjs_set(_ass_multi.mjs, _ass_multi.val, name, ~0, value)
46
62typedef enum {
63 JsForeignMagicStart = 0x15BAD000,
64 JsForeignMagic_JsEventLoopContract,
65} JsForeignMagic;
66
67// Are you tired of your silly little JS+C glue code functions being 75%
68// argument validation code and 25% actual logic? Introducing: ASS (Argument
69// Schema for Scripts)! ASS is a set of macros that reduce the typical
70// boilerplate code of "check argument count, get arguments, validate arguments,
71// extract C values from arguments" down to just one line!
72
77#define JS_EXACTLY ==
82#define JS_AT_LEAST >=
83
84#define JS_ENUM_MAP(var_name, ...) \
85 static const JsEnumMapping var_name##_mapping[] = { \
86 {NULL, sizeof(var_name)}, \
87 __VA_ARGS__, \
88 {NULL, 0}, \
89 };
90
91typedef struct {
92 const char* name;
93 size_t value;
95
96typedef struct {
97 void* out;
98 int (*validator)(mjs_val_t);
99 void (*converter)(struct mjs*, mjs_val_t*, void* out, const void* extra);
100 const char* expected_type;
101 bool (*extended_validator)(struct mjs*, mjs_val_t, const void* extra);
102 const void* extra_data;
104
105static inline void _js_to_int32(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
106 UNUSED(extra);
107 *(int32_t*)out = mjs_get_int32(mjs, *in);
108}
109#define JS_ARG_INT32(out) ((_js_arg_decl){out, mjs_is_number, _js_to_int32, "number", NULL, NULL})
110
111static inline void _js_to_ptr(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
112 UNUSED(extra);
113 *(void**)out = mjs_get_ptr(mjs, *in);
114}
115#define JS_ARG_PTR(out) \
116 ((_js_arg_decl){out, mjs_is_foreign, _js_to_ptr, "opaque pointer", NULL, NULL})
117
118static inline void _js_to_string(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
119 UNUSED(extra);
120 *(const char**)out = mjs_get_string(mjs, in, NULL);
121}
122#define JS_ARG_STR(out) ((_js_arg_decl){out, mjs_is_string, _js_to_string, "string", NULL, NULL})
123
124static inline void _js_to_bool(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
125 UNUSED(extra);
126 *(bool*)out = !!mjs_get_bool(mjs, *in);
127}
128#define JS_ARG_BOOL(out) ((_js_arg_decl){out, mjs_is_boolean, _js_to_bool, "boolean", NULL, NULL})
129
130static inline void _js_passthrough(struct mjs* mjs, mjs_val_t* in, void* out, const void* extra) {
131 UNUSED(extra);
132 UNUSED(mjs);
133 *(mjs_val_t*)out = *in;
134}
135#define JS_ARG_ANY(out) ((_js_arg_decl){out, NULL, _js_passthrough, "any", NULL, NULL})
136#define JS_ARG_OBJ(out) ((_js_arg_decl){out, mjs_is_object, _js_passthrough, "any", NULL, NULL})
137#define JS_ARG_FN(out) \
138 ((_js_arg_decl){out, mjs_is_function, _js_passthrough, "function", NULL, NULL})
139#define JS_ARG_ARR(out) ((_js_arg_decl){out, mjs_is_array, _js_passthrough, "array", NULL, NULL})
140
141static inline bool _js_validate_struct(struct mjs* mjs, mjs_val_t val, const void* extra) {
142 JsForeignMagic expected_magic = (JsForeignMagic)(size_t)extra;
143 JsForeignMagic struct_magic = *(JsForeignMagic*)mjs_get_ptr(mjs, val);
144 return struct_magic == expected_magic;
145}
146#define JS_ARG_STRUCT(type, out) \
147 ((_js_arg_decl){ \
148 out, \
149 mjs_is_foreign, \
150 _js_to_ptr, \
151 #type, \
152 _js_validate_struct, \
153 (void*)JsForeignMagic##_##type})
154
155static inline bool _js_validate_obj_w_struct(struct mjs* mjs, mjs_val_t val, const void* extra) {
156 JsForeignMagic expected_magic = (JsForeignMagic)(size_t)extra;
157 JsForeignMagic struct_magic = *(JsForeignMagic*)JS_GET_INST(mjs, val);
158 return struct_magic == expected_magic;
159}
160#define JS_ARG_OBJ_WITH_STRUCT(type, out) \
161 ((_js_arg_decl){ \
162 out, \
163 mjs_is_object, \
164 _js_passthrough, \
165 #type, \
166 _js_validate_obj_w_struct, \
167 (void*)JsForeignMagic##_##type})
168
169static inline bool _js_validate_enum(struct mjs* mjs, mjs_val_t val, const void* extra) {
170 for(const JsEnumMapping* mapping = (JsEnumMapping*)extra + 1; mapping->name; mapping++)
171 if(strcmp(mapping->name, mjs_get_string(mjs, &val, NULL)) == 0) return true;
172 return false;
173}
174static inline void
175 _js_convert_enum(struct mjs* mjs, mjs_val_t* val, void* out, const void* extra) {
176 const JsEnumMapping* mapping = (JsEnumMapping*)extra;
177 size_t size = mapping->value; // get enum size from first entry
178 for(mapping++; mapping->name; mapping++) {
179 if(strcmp(mapping->name, mjs_get_string(mjs, val, NULL)) == 0) {
180 if(size == 1)
181 *(uint8_t*)out = mapping->value;
182 else if(size == 2)
183 *(uint16_t*)out = mapping->value;
184 else if(size == 4)
185 *(uint32_t*)out = mapping->value;
186 else if(size == 8)
187 *(uint64_t*)out = mapping->value;
188 return;
189 }
190 }
191 // unreachable, thanks to _js_validate_enum
192}
193#define JS_ARG_ENUM(var_name, name) \
194 ((_js_arg_decl){ \
195 &var_name, \
196 mjs_is_string, \
197 _js_convert_enum, \
198 name " enum", \
199 _js_validate_enum, \
200 var_name##_mapping})
201
202//-V:JS_FETCH_ARGS_OR_RETURN:1008
211#define JS_FETCH_ARGS_OR_RETURN(mjs, arg_operator, ...) \
212 _js_arg_decl _js_args[] = {__VA_ARGS__}; \
213 int _js_arg_cnt = COUNT_OF(_js_args); \
214 mjs_val_t _js_arg_vals[_js_arg_cnt]; \
215 if(!(mjs_nargs(mjs) arg_operator _js_arg_cnt)) \
216 JS_ERROR_AND_RETURN( \
217 mjs, \
218 MJS_BAD_ARGS_ERROR, \
219 "expected %s%d arguments, got %d", \
220 #arg_operator, \
221 _js_arg_cnt, \
222 mjs_nargs(mjs)); \
223 for(int _i = 0; _i < _js_arg_cnt; _i++) { \
224 _js_arg_vals[_i] = mjs_arg(mjs, _i); \
225 if(_js_args[_i].validator) \
226 if(!_js_args[_i].validator(_js_arg_vals[_i])) \
227 JS_ERROR_AND_RETURN( \
228 mjs, \
229 MJS_BAD_ARGS_ERROR, \
230 "argument %d: expected %s", \
231 _i, \
232 _js_args[_i].expected_type); \
233 if(_js_args[_i].extended_validator) \
234 if(!_js_args[_i].extended_validator(mjs, _js_arg_vals[_i], _js_args[_i].extra_data)) \
235 JS_ERROR_AND_RETURN( \
236 mjs, \
237 MJS_BAD_ARGS_ERROR, \
238 "argument %d: expected %s", \
239 _i, \
240 _js_args[_i].expected_type); \
241 _js_args[_i].converter( \
242 mjs, &_js_arg_vals[_i], _js_args[_i].out, _js_args[_i].extra_data); \
243 }
244
250#define JS_ERROR_AND_RETURN(mjs, error_code, ...) \
251 do { \
252 mjs_prepend_errorf(mjs, error_code, __VA_ARGS__); \
253 mjs_return(mjs, MJS_UNDEFINED); \
254 return; \
255 } while(0)
256
257typedef struct JsModules JsModules;
258
259typedef void* (*JsModuleConstructor)(struct mjs* mjs, mjs_val_t* object, JsModules* modules);
260typedef void (*JsModuleDestructor)(void* inst);
261
262typedef struct {
263 char* name;
264 JsModuleConstructor create;
265 JsModuleDestructor destroy;
266 const ElfApiInterface* api_interface;
268
269JsModules* js_modules_create(struct mjs* mjs, CompositeApiResolver* resolver);
270
271void js_modules_destroy(JsModules* modules);
272
273mjs_val_t js_module_require(JsModules* modules, const char* name, size_t name_len);
274
281void* js_module_get(JsModules* modules, const char* name);
282
286void js_sdk_compatibility_status(struct mjs* mjs);
287
291void js_is_sdk_compatible(struct mjs* mjs);
292
296void js_check_sdk_compatibility(struct mjs* mjs);
297
301void js_does_sdk_support(struct mjs* mjs);
302
306void js_check_sdk_features(struct mjs* mjs);
Flipper application.
Definition js_modules.h:96
Definition composite_resolver.c:10
Interface for ELF loader to resolve symbols.
Definition elf_api_interface.h:9
Definition js_modules.h:91
Definition js_modules.h:262
Definition js_modules.c:40
Definition mjs_core.h:63