mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-25 22:32:29 +03:00
0154018363
* FBT: cdefines to env, libs order * API: strtod, modf, itoa, calloc * Apps: elk js * Apps: mjs * JS: scripts as assets * mjs: composite resolver * mjs: stack trace * ELK JS example removed * MJS thread, MJS lib modified to support script interruption * JS console UI * Module system, BadUSB bindings rework * JS notifications, simple dialog, BadUSB demo * Custom dialogs, dialog demo * MJS as system library, some dirty hacks to make it compile * Plugin-based js modules * js_uart(BadUART) module * js_uart: support for byte array arguments * Script icon and various fixes * File browser: multiple extensions filter, running js scripts from app loader * Running js scripts from archive browser * JS Runner as system app * Example scripts moved to /ext/apps/Scripts * JS bytecode listing generation * MJS builtin printf cleanup * JS examples cleanup * mbedtls version fix * Unused lib cleanup * Making PVS happy & TODOs cleanup * TODOs cleanup #2 * MJS: initial typed arrays support * JS: fix mem leak in uart destructor Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
163 lines
5.1 KiB
C
163 lines
5.1 KiB
C
/*
|
|
* Copyright (c) 2017 Cesanta Software Limited
|
|
* All rights reserved
|
|
*/
|
|
|
|
#include "mjs_bcode.h"
|
|
#include "mjs_core.h"
|
|
#include "mjs_dataview.h"
|
|
#include "mjs_exec.h"
|
|
#include "mjs_gc.h"
|
|
#include "mjs_internal.h"
|
|
#include "mjs_json.h"
|
|
#include "mjs_object.h"
|
|
#include "mjs_primitive.h"
|
|
#include "mjs_string.h"
|
|
#include "mjs_util.h"
|
|
#include "mjs_array_buf.h"
|
|
|
|
/*
|
|
* If the file with the given filename was already loaded, returns the
|
|
* corresponding bcode part; otherwise returns NULL.
|
|
*/
|
|
static struct mjs_bcode_part* mjs_get_loaded_file_bcode(struct mjs* mjs, const char* filename) {
|
|
int parts_cnt = mjs_bcode_parts_cnt(mjs);
|
|
int i;
|
|
|
|
if(filename == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
for(i = 0; i < parts_cnt; i++) {
|
|
struct mjs_bcode_part* bp = mjs_bcode_part_get(mjs, i);
|
|
const char* cur_fn = mjs_get_bcode_filename(mjs, bp);
|
|
if(strcmp(filename, cur_fn) == 0) {
|
|
return bp;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void mjs_load(struct mjs* mjs) {
|
|
mjs_val_t res = MJS_UNDEFINED;
|
|
mjs_val_t arg0 = mjs_arg(mjs, 0);
|
|
mjs_val_t arg1 = mjs_arg(mjs, 1);
|
|
int custom_global = 0; /* whether the custom global object was provided */
|
|
|
|
if(mjs_is_string(arg0)) {
|
|
const char* path = mjs_get_cstring(mjs, &arg0);
|
|
struct mjs_bcode_part* bp = NULL;
|
|
mjs_err_t ret;
|
|
|
|
if(mjs_is_object(arg1)) {
|
|
custom_global = 1;
|
|
push_mjs_val(&mjs->scopes, arg1);
|
|
}
|
|
bp = mjs_get_loaded_file_bcode(mjs, path);
|
|
if(bp == NULL) {
|
|
/* File was not loaded before, so, load */
|
|
ret = mjs_exec_file(mjs, path, &res);
|
|
} else {
|
|
/*
|
|
* File was already loaded before, so if it was evaluated successfully,
|
|
* then skip the evaluation at all (and assume MJS_OK); otherwise
|
|
* re-evaluate it again.
|
|
*
|
|
* However, if the custom global object was provided, then reevaluate
|
|
* the file in any case.
|
|
*/
|
|
if(bp->exec_res != MJS_OK || custom_global) {
|
|
ret = mjs_execute(mjs, bp->start_idx, &res);
|
|
} else {
|
|
ret = MJS_OK;
|
|
}
|
|
}
|
|
if(ret != MJS_OK) {
|
|
/*
|
|
* arg0 and path might be invalidated by executing a file, so refresh
|
|
* them
|
|
*/
|
|
arg0 = mjs_arg(mjs, 0);
|
|
path = mjs_get_cstring(mjs, &arg0);
|
|
mjs_prepend_errorf(mjs, ret, "failed to exec file \"%s\"", path);
|
|
goto clean;
|
|
}
|
|
|
|
clean:
|
|
if(custom_global) {
|
|
mjs_pop_val(&mjs->scopes);
|
|
}
|
|
}
|
|
mjs_return(mjs, res);
|
|
}
|
|
|
|
static void mjs_get_mjs(struct mjs* mjs) {
|
|
mjs_return(mjs, mjs_mk_foreign(mjs, mjs));
|
|
}
|
|
|
|
static void mjs_chr(struct mjs* mjs) {
|
|
mjs_val_t arg0 = mjs_arg(mjs, 0), res = MJS_NULL;
|
|
int n = mjs_get_int(mjs, arg0);
|
|
if(mjs_is_number(arg0) && n >= 0 && n <= 255) {
|
|
uint8_t s = n;
|
|
res = mjs_mk_string(mjs, (const char*)&s, sizeof(s), 1);
|
|
}
|
|
mjs_return(mjs, res);
|
|
}
|
|
|
|
static void mjs_do_gc(struct mjs* mjs) {
|
|
mjs_val_t arg0 = mjs_arg(mjs, 0);
|
|
mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0);
|
|
mjs_return(mjs, arg0);
|
|
}
|
|
|
|
static void mjs_s2o(struct mjs* mjs) {
|
|
mjs_return(
|
|
mjs,
|
|
mjs_struct_to_obj(
|
|
mjs,
|
|
mjs_get_ptr(mjs, mjs_arg(mjs, 0)),
|
|
(const struct mjs_c_struct_member*)mjs_get_ptr(mjs, mjs_arg(mjs, 1))));
|
|
}
|
|
|
|
void mjs_init_builtin(struct mjs* mjs, mjs_val_t obj) {
|
|
mjs_val_t v;
|
|
|
|
mjs_set(mjs, obj, "global", ~0, obj);
|
|
|
|
mjs_set(mjs, obj, "load", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_load));
|
|
mjs_set(mjs, obj, "ffi", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_ffi_call));
|
|
mjs_set(
|
|
mjs, obj, "ffi_cb_free", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_ffi_cb_free));
|
|
mjs_set(mjs, obj, "mkstr", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_mkstr));
|
|
mjs_set(mjs, obj, "getMJS", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_get_mjs));
|
|
mjs_set(mjs, obj, "die", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_die));
|
|
mjs_set(mjs, obj, "gc", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_do_gc));
|
|
mjs_set(mjs, obj, "chr", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_chr));
|
|
mjs_set(mjs, obj, "s2o", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_s2o));
|
|
|
|
/*
|
|
* Populate JSON.parse() and JSON.stringify()
|
|
*/
|
|
// v = mjs_mk_object(mjs);
|
|
// mjs_set(
|
|
// mjs, v, "stringify", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_op_json_stringify));
|
|
// mjs_set(mjs, v, "parse", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_op_json_parse));
|
|
// mjs_set(mjs, obj, "JSON", ~0, v);
|
|
|
|
/*
|
|
* Populate Object.create()
|
|
*/
|
|
v = mjs_mk_object(mjs);
|
|
mjs_set(mjs, v, "create", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_op_create_object));
|
|
mjs_set(mjs, obj, "Object", ~0, v);
|
|
|
|
/*
|
|
* Populate numeric stuff
|
|
*/
|
|
mjs_set(mjs, obj, "NaN", ~0, MJS_TAG_NAN);
|
|
mjs_set(mjs, obj, "isNaN", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_op_isnan));
|
|
|
|
mjs_init_builtin_array_buf(mjs, obj);
|
|
}
|