mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 04:41:26 +04:00
* Update and fix JS docs This could really use some automation, atleast for API reference There are TypeScript definitions and typedocs, we don't need to be monkeys copying and reformatting this to API reference by hand * Fix bugged character * JS: Fix Number.toString() with decimals * Fix * Forgot this one * docs: mention per-view child format * Added @portasynthinca3 to docs' codeowners * Updated CODEOWNERS --------- Co-authored-by: Anna Antonenko <portasynthinca3@gmail.com> Co-authored-by: hedger <hedger@nanode.su> Co-authored-by: hedger <hedger@users.noreply.github.com>
204 lines
4.6 KiB
C
204 lines
4.6 KiB
C
/*
|
|
* Copyright (c) 2017 Cesanta Software Limited
|
|
* All rights reserved
|
|
*/
|
|
|
|
#include "mjs_core.h"
|
|
#include "mjs_internal.h"
|
|
#include "mjs_primitive.h"
|
|
#include "mjs_string_public.h"
|
|
#include "mjs_util.h"
|
|
|
|
#include <float.h>
|
|
|
|
mjs_val_t mjs_mk_null(void) {
|
|
return MJS_NULL;
|
|
}
|
|
|
|
int mjs_is_null(mjs_val_t v) {
|
|
return v == MJS_NULL;
|
|
}
|
|
|
|
mjs_val_t mjs_mk_undefined(void) {
|
|
return MJS_UNDEFINED;
|
|
}
|
|
|
|
int mjs_is_undefined(mjs_val_t v) {
|
|
return v == MJS_UNDEFINED;
|
|
}
|
|
|
|
mjs_val_t mjs_mk_number(struct mjs* mjs, double v) {
|
|
mjs_val_t res;
|
|
(void)mjs;
|
|
/* not every NaN is a JS NaN */
|
|
if(isnan(v)) {
|
|
res = MJS_TAG_NAN;
|
|
} else {
|
|
union {
|
|
double d;
|
|
mjs_val_t r;
|
|
} u;
|
|
u.d = v;
|
|
res = u.r;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static double get_double(mjs_val_t v) {
|
|
union {
|
|
double d;
|
|
mjs_val_t v;
|
|
} u;
|
|
u.v = v;
|
|
/* Due to NaN packing, any non-numeric value is already a valid NaN value */
|
|
return u.d;
|
|
}
|
|
|
|
double mjs_get_double(struct mjs* mjs, mjs_val_t v) {
|
|
(void)mjs;
|
|
return get_double(v);
|
|
}
|
|
|
|
int mjs_get_int(struct mjs* mjs, mjs_val_t v) {
|
|
(void)mjs;
|
|
/*
|
|
* NOTE(dfrank): without double cast, all numbers >= 0x80000000 are always
|
|
* converted to exactly 0x80000000.
|
|
*/
|
|
return (int)(unsigned int)get_double(v);
|
|
}
|
|
|
|
int32_t mjs_get_int32(struct mjs* mjs, mjs_val_t v) {
|
|
(void)mjs;
|
|
return (int32_t)get_double(v);
|
|
}
|
|
|
|
int mjs_is_number(mjs_val_t v) {
|
|
return v == MJS_TAG_NAN || !isnan(get_double(v));
|
|
}
|
|
|
|
mjs_val_t mjs_mk_boolean(struct mjs* mjs, int v) {
|
|
(void)mjs;
|
|
return (v ? 1 : 0) | MJS_TAG_BOOLEAN;
|
|
}
|
|
|
|
int mjs_get_bool(struct mjs* mjs, mjs_val_t v) {
|
|
(void)mjs;
|
|
if(mjs_is_boolean(v)) {
|
|
return v & 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int mjs_is_boolean(mjs_val_t v) {
|
|
return (v & MJS_TAG_MASK) == MJS_TAG_BOOLEAN;
|
|
}
|
|
|
|
#define MJS_IS_POINTER_LEGIT(n) \
|
|
(((n) & MJS_TAG_MASK) == 0 || ((n) & MJS_TAG_MASK) == (~0 & MJS_TAG_MASK))
|
|
|
|
MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs* mjs, void* p) {
|
|
uint64_t n = ((uint64_t)(uintptr_t)p);
|
|
|
|
if(!MJS_IS_POINTER_LEGIT(n)) {
|
|
mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid pointer value: %p", p);
|
|
}
|
|
return n & ~MJS_TAG_MASK;
|
|
}
|
|
|
|
MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void* p) {
|
|
uint64_t n = ((uint64_t)(uintptr_t)p);
|
|
|
|
assert(MJS_IS_POINTER_LEGIT(n));
|
|
return n & ~MJS_TAG_MASK;
|
|
}
|
|
|
|
MJS_PRIVATE void* get_ptr(mjs_val_t v) {
|
|
return (void*)(uintptr_t)(v & 0xFFFFFFFFFFFFUL);
|
|
}
|
|
|
|
void* mjs_get_ptr(struct mjs* mjs, mjs_val_t v) {
|
|
(void)mjs;
|
|
if(!mjs_is_foreign(v)) {
|
|
return NULL;
|
|
}
|
|
return get_ptr(v);
|
|
}
|
|
|
|
mjs_val_t mjs_mk_foreign(struct mjs* mjs, void* p) {
|
|
(void)mjs;
|
|
return mjs_pointer_to_value(mjs, p) | MJS_TAG_FOREIGN;
|
|
}
|
|
|
|
mjs_val_t mjs_mk_foreign_func(struct mjs* mjs, mjs_func_ptr_t fn) {
|
|
union {
|
|
mjs_func_ptr_t fn;
|
|
void* p;
|
|
} u;
|
|
u.fn = fn;
|
|
(void)mjs;
|
|
return mjs_pointer_to_value(mjs, u.p) | MJS_TAG_FOREIGN;
|
|
}
|
|
|
|
int mjs_is_foreign(mjs_val_t v) {
|
|
return (v & MJS_TAG_MASK) == MJS_TAG_FOREIGN;
|
|
}
|
|
|
|
mjs_val_t mjs_mk_function(struct mjs* mjs, size_t off) {
|
|
(void)mjs;
|
|
return (mjs_val_t)off | MJS_TAG_FUNCTION;
|
|
}
|
|
|
|
int mjs_is_function(mjs_val_t v) {
|
|
return (v & MJS_TAG_MASK) == MJS_TAG_FUNCTION;
|
|
}
|
|
|
|
MJS_PRIVATE void mjs_op_isnan(struct mjs* mjs) {
|
|
mjs_val_t ret = MJS_UNDEFINED;
|
|
mjs_val_t val = mjs_arg(mjs, 0);
|
|
|
|
ret = mjs_mk_boolean(mjs, val == MJS_TAG_NAN);
|
|
|
|
mjs_return(mjs, ret);
|
|
}
|
|
|
|
MJS_PRIVATE void mjs_number_to_string(struct mjs* mjs) {
|
|
mjs_val_t ret = MJS_UNDEFINED;
|
|
mjs_val_t base_v = MJS_UNDEFINED;
|
|
int32_t base = 10;
|
|
double num;
|
|
|
|
/* get number from `this` */
|
|
if(!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_NUMBER, NULL)) {
|
|
goto clean;
|
|
}
|
|
num = mjs_get_double(mjs, mjs->vals.this_obj);
|
|
|
|
if(mjs_nargs(mjs) >= 1) {
|
|
/* get base from arg 0 */
|
|
if(!mjs_check_arg(mjs, 0, "base", MJS_TYPE_NUMBER, &base_v)) {
|
|
goto clean;
|
|
}
|
|
base = mjs_get_int(mjs, base_v);
|
|
}
|
|
|
|
if(base != 10 || floor(num) == num) {
|
|
char tmp_str[] = "-2147483648";
|
|
itoa((int32_t)num, tmp_str, base);
|
|
ret = mjs_mk_string(mjs, tmp_str, ~0, true);
|
|
} else {
|
|
char tmp_str[] = "2.22514337200000e-308";
|
|
snprintf(tmp_str, sizeof(tmp_str), "%.*g", DBL_DIG, num);
|
|
size_t len = strlen(tmp_str);
|
|
while(len && tmp_str[len - 1] == '0') {
|
|
len--;
|
|
}
|
|
tmp_str[len] = '\0';
|
|
ret = mjs_mk_string(mjs, tmp_str, ~0, true);
|
|
}
|
|
|
|
clean:
|
|
mjs_return(mjs, ret);
|
|
}
|