/* * QuickJS Javascript Engine * * Copyright (c) 2017-2021 Fabrice Bellard * Copyright (c) 2017-2021 Charlie Gordon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef QUICKJS_H #define QUICKJS_H #include #include #include #ifdef __cplusplus extern "C" { #endif #if defined(__GNUC__) || defined(__clang__) #define __js_printf_like(f, a) __attribute__ ((format (printf, f, a))) #else #define __js_printf_like(a, b) #endif // #define BINARY16 // 16 bit word type (half) // #define BINARY32 // 32 bit word type (float) // #define BINARY64 // 64 bit word type (double) // #define DEC64 // 64 bit word type (dec) enum mist_obj_type { OBJ_ARRAY = 0, OBJ_BLOB = 1, OBJ_TEXT = 2, OBJ_RECORD = 3, // js style objects OBJ_FUNCTION = 4, OBJ_CODE = 5, OBJ_FRAME = 6, OBJ_FORWARD = 7 }; #define OBJHDR_S_BIT 3u #define OBJHDR_P_BIT 4u #define OBJHDR_A_BIT 5u #define OBJHDR_R_BIT 7u #define OBJHDR_FLAG(bit) ((objhdr_t)1ull << (bit)) #define OBJHDR_S_MASK OBJHDR_FLAG (OBJHDR_S_BIT) #define OBJHDR_P_MASK OBJHDR_FLAG (OBJHDR_P_BIT) #define OBJHDR_A_MASK OBJHDR_FLAG (OBJHDR_A_BIT) #define OBJHDR_R_MASK OBJHDR_FLAG (OBJHDR_R_BIT) typedef uint64_t word_t; // one actor-memory word typedef uint64_t objhdr_t; // header word typedef uint64_t objref_t; // 56-bit word address (0 = null) static inline uint8_t objhdr_type (objhdr_t h) { return (uint8_t)(h & 7u); } static inline int objhdr_s (objhdr_t h) { return (h & OBJHDR_S_MASK) != 0; } /* Half: 10 bits Float: 23 bits Double: 52 bits Dec16: 11 bits Dec32: 26 bits Dec64: 56 bits On double builds, 48 bits On Dec64, max */ #define JS_BOOL int typedef struct JSRuntime JSRuntime; // the entire VM typedef struct JSContext JSContext; // Each actor typedef struct JSClass JSClass; typedef struct JSFunctionBytecode JSFunctionBytecode; typedef uint32_t JSClassID; /* Forward declaration - JSGCRef moved after JSValue definition */ struct JSGCRef; /* ============================================================ Mist Value Encoding (LSB-based type discrimination) ============================================================ 64-bit builds: LSB = 0 → 31-bit signed integer (value >> 1) LSB = 001 → 61-bit pointer (aligned, clear low 3 bits) LSB = 101 → Short float (61-bit, 3 fewer exponent bits than double) LSB = 11 → Special tag (next 3 bits = subtype, 5 bits total) 32-bit builds: LSB = 0 → 31-bit signed integer LSB = 01 → 30-bit pointer LSB = 11 → Special tag (next 3 bits = subtype) ============================================================ */ #if INTPTR_MAX >= INT64_MAX #define JS_PTR64 #define JS_PTR64_DEF(a) a typedef uint64_t JSValue; #define JSW 8 #else typedef uint32_t JSValue; #define JSW 4 #define JS_PTR64_DEF(a) #endif #define JSValue JSValue /* JSValueConst is just JSValue (const is not needed in value semantics) */ typedef JSValue JSValueConst; /* LSB-based tags */ enum { /* Primary tags (low bits) */ JS_TAG_INT = 0, /* LSB = 0 */ JS_TAG_PTR = 1, /* LSB = 01 */ #ifdef JS_PTR64 JS_TAG_SHORT_FLOAT = 5, /* LSB = 101 */ #endif JS_TAG_SPECIAL = 3, /* LSB = 11 */ /* Special subtypes (5 bits: xxxx11) */ JS_TAG_BOOL = 0x03, /* 00011 */ JS_TAG_NULL = 0x07, /* 00111 */ JS_TAG_EXCEPTION = 0x0F, /* 01111 */ JS_TAG_UNINITIALIZED = 0x17, /* 10111 */ JS_TAG_STRING_IMM = 0x1B, /* 11011 - immediate ASCII (up to 7 chars) */ JS_TAG_CATCH_OFFSET = 0x1F, /* 11111 */ }; /* Compatibility tag aliases for external code */ #define JS_TAG_STRING JS_TAG_STRING_IMM /* Alias: text/string type */ #define JS_TAG_FLOAT64 JS_TAG_SHORT_FLOAT /* Alias: floats use short float encoding */ #define JS_EMPTY_TEXT ((JSValue)JS_TAG_STRING_IMM) /* JSGCRef - for rooting values during GC */ typedef struct JSGCRef { JSValue val; struct JSGCRef *prev; } JSGCRef; /* stack of JSGCRef */ JSValue *JS_PushGCRef(JSContext *ctx, JSGCRef *ref); JSValue JS_PopGCRef(JSContext *ctx, JSGCRef *ref); #define JS_PUSH_VALUE(ctx, v) do { JS_PushGCRef(ctx, &v ## _ref); v ## _ref.val = v; } while (0) #define JS_POP_VALUE(ctx, v) v = JS_PopGCRef(ctx, &v ## _ref) /* list of JSGCRef (they can be removed in any order, slower) */ JSValue *JS_AddGCRef(JSContext *ctx, JSGCRef *ref); void JS_DeleteGCRef(JSContext *ctx, JSGCRef *ref); /* ============================================================ Value Extraction ============================================================ */ /* Get primary tag (low 2-3 bits) */ static inline int JS_VALUE_GET_TAG (JSValue v) { #ifdef JS_PTR64 if ((v & 1) == 0) return JS_TAG_INT; if ((v & 7) == JS_TAG_SHORT_FLOAT) return JS_TAG_SHORT_FLOAT; if ((v & 3) == JS_TAG_PTR) return JS_TAG_PTR; return (int)(v & 0x1F); /* special tag */ #else if ((v & 1) == 0) return JS_TAG_INT; if ((v & 3) == JS_TAG_PTR) return JS_TAG_PTR; return (int)(v & 0x1F); #endif } #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG (v) /* Extract 31-bit signed int (when LSB=0) */ #define JS_VALUE_GET_INT(v) ((int32_t)((int64_t)(v) >> 1)) /* Extract bool value from special tag */ #define JS_VALUE_GET_BOOL(v) ((int)((v) >> 5) & 1) /* Extract special tag payload (bits 5+) */ #define JS_VALUE_GET_SPECIAL_PAYLOAD(v) ((int32_t)((v) >> 5)) /* ============================================================ Value Creation ============================================================ */ #define JS_MKVAL(tag, val) _JS_MkVal (tag, val) static inline JSValue _JS_MkVal (int tag, int32_t val) { if (tag == JS_TAG_INT) { return ((JSValue)(uint32_t)val << 1); } /* Special tags encode payload in upper bits */ return ((JSValue)tag) | ((JSValue)(uint32_t)val << 5); } /* ============================================================ Short Float (64-bit only) Range: ~+-3.4e38 (8-bit exponent vs double's 11-bit) Out of range → JS_NULL ============================================================ */ #ifdef JS_PTR64 static inline JSValue __JS_NewFloat64 (JSContext *ctx, double d) { union { double d; uint64_t u; } u; u.d = d; uint64_t sign = u.u >> 63; int exp = (u.u >> 52) & 0x7FF; uint64_t mantissa = u.u & ((1ULL << 52) - 1); /* Zero → short float zero (always +0, no -0) */ if (exp == 0 && mantissa == 0) { return JS_TAG_SHORT_FLOAT; } /* NaN/Inf → NULL */ if (exp == 0x7FF) { return JS_MKVAL (JS_TAG_NULL, 0); } /* Subnormals → zero */ if (exp == 0) { return (sign << 63) | JS_TAG_SHORT_FLOAT; } /* Convert exponent: double bias 1023 → short bias 127 */ int short_exp = exp - 1023 + 127; if (short_exp < 1 || short_exp > 254) { return JS_MKVAL (JS_TAG_NULL, 0); /* out of range */ } /* Prefer integer if exact */ if (d >= INT32_MIN && d <= INT32_MAX) { int32_t i = (int32_t)d; if ((double)i == d) { return JS_MKVAL (JS_TAG_INT, i); } } /* Encode: [sign:1][exp:8][mantissa:52][tag:3] */ return (sign << 63) | ((uint64_t)short_exp << 55) | (mantissa << 3) | JS_TAG_SHORT_FLOAT; } static inline double JS_VALUE_GET_FLOAT64 (JSValue v) { if ((v & 7) != JS_TAG_SHORT_FLOAT) return 0.0; uint64_t sign = v >> 63; uint64_t short_exp = (v >> 55) & 0xFF; uint64_t mantissa = (v >> 3) & ((1ULL << 52) - 1); if (short_exp == 0) return 0.0; /* Always +0, no -0 */ uint64_t exp = short_exp - 127 + 1023; union { double d; uint64_t u; } u; u.u = (sign << 63) | (exp << 52) | mantissa; return u.d; } #define JS_TAG_IS_FLOAT64(tag) ((tag) == JS_TAG_SHORT_FLOAT) #define JS_NAN JS_MKVAL (JS_TAG_NULL, 0) #else /* 32-bit: no short float, use boxed double */ static inline JSValue __JS_NewFloat64 (JSContext *ctx, double d); /* forward decl */ static inline double JS_VALUE_GET_FLOAT64 (JSValue v); #define JS_TAG_IS_FLOAT64(tag) (0) #define JS_NAN JS_MKVAL (JS_TAG_NULL, 0) #endif /* JS_PTR64 */ /* ============================================================ Type Checks ============================================================ */ static inline JS_BOOL JS_IsInt (JSValue v) { return (v & 1) == 0; } static inline JS_BOOL JS_IsPtr (JSValue v) { return (v & 7) == JS_TAG_PTR; } static inline JS_BOOL JS_IsSpecial (JSValue v) { return (v & 3) == JS_TAG_SPECIAL; } #ifdef JS_PTR64 static inline JS_BOOL JS_IsShortFloat (JSValue v) { return (v & 7) == JS_TAG_SHORT_FLOAT; } #endif #define JS_VALUE_IS_BOTH_INT(v1, v2) (((v1) & 1) == 0 && ((v2) & 1) == 0) #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) \ (JS_IsShortFloat (v1) && JS_IsShortFloat (v2)) /* ============================================================ Special Constants ============================================================ */ #define JS_NULL ((JSValue)JS_TAG_NULL) #define JS_FALSE ((JSValue)JS_TAG_BOOL) #define JS_TRUE ((JSValue)(JS_TAG_BOOL | (1 << 5))) #define JS_EXCEPTION ((JSValue)JS_TAG_EXCEPTION) #define JS_UNINITIALIZED ((JSValue)JS_TAG_UNINITIALIZED) /* flags for object properties - simplified model: - No per-property writable/configurable (use stone() for immutability) - Text keys are enumerable, object keys are not */ #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, VARREF */ #define JS_PROP_NORMAL (0 << 4) #define JS_PROP_VARREF (2 << 4) /* used internally for closures */ #ifndef JS_DEFAULT_STACK_SIZE #define JS_DEFAULT_STACK_SIZE (1024 * 1024) #endif /* Internal compile flags */ #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* internal use */ typedef JSValue JSCFunction (JSContext *ctx, JSValue this_val, int argc, JSValue *argv); typedef JSValue JSCFunctionMagic (JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); typedef JSValue JSCFunctionData (JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic, JSValue *data); typedef struct JSMallocState { size_t malloc_count; size_t malloc_size; size_t malloc_limit; void *opaque; /* user opaque */ } JSMallocState; typedef struct JSMallocFunctions { void *(*js_malloc) (JSMallocState *s, size_t size); void (*js_free) (JSMallocState *s, void *ptr); void *(*js_realloc) (JSMallocState *s, void *ptr, size_t size); size_t (*js_malloc_usable_size) (const void *ptr); } JSMallocFunctions; typedef struct JSGCObjectHeader JSGCObjectHeader; JSValue JS_Stone (JSContext *ctx, JSValue this_val); JSRuntime *JS_NewRuntime (void); /* info lifetime must exceed that of rt */ void JS_SetRuntimeInfo (JSRuntime *rt, const char *info); void JS_SetMemoryLimit (JSRuntime *rt, size_t limit); /* use 0 to disable maximum stack size check */ void JS_SetMaxStackSize (JSRuntime *rt, size_t stack_size); /* should be called when changing thread to update the stack top value used to check stack overflow. */ void JS_UpdateStackTop (JSRuntime *rt); void JS_FreeRuntime (JSRuntime *rt); void *JS_GetRuntimeOpaque (JSRuntime *rt); void JS_SetRuntimeOpaque (JSRuntime *rt, void *opaque); typedef void JS_MarkFunc (JSRuntime *rt, JSGCObjectHeader *gp); /* JS_MarkValue is a no-op with copying GC (values are traced from roots) */ void JS_MarkValue (JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); JS_BOOL JS_IsLiveObject (JSRuntime *rt, JSValue obj); JSContext *JS_NewContext (JSRuntime *rt); void JS_FreeContext (JSContext *s); JSContext *JS_DupContext (JSContext *ctx); JSContext *JS_GetContext (JSRuntime *rt); void *JS_GetContextOpaque (JSContext *ctx); void JS_SetContextOpaque (JSContext *ctx, void *opaque); JSRuntime *JS_GetRuntime (JSContext *ctx); void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj); JSValue JS_GetClassProto (JSContext *ctx, JSClassID class_id); JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size); typedef struct JSMemoryUsage { int64_t malloc_size, malloc_limit, memory_used_size; int64_t malloc_count; int64_t memory_used_count; int64_t str_count, str_size; int64_t obj_count, obj_size; int64_t prop_count, prop_size; int64_t shape_count, shape_size; int64_t js_func_count, js_func_size, js_func_code_size; int64_t js_func_pc2line_count, js_func_pc2line_size; int64_t c_func_count, array_count; int64_t fast_array_count, fast_array_elements; int64_t binary_object_count, binary_object_size; } JSMemoryUsage; void JS_ComputeMemoryUsage (JSRuntime *rt, JSMemoryUsage *s); void JS_DumpMemoryUsage (FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); typedef void JSClassFinalizer (JSRuntime *rt, JSValue val); typedef void JSClassGCMark (JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); typedef JSValue JSClassCall (JSContext *ctx, JSValue func_obj, JSValue this_val, int argc, JSValue *argv, int flags); typedef struct JSClassDef { const char *class_name; JSClassFinalizer *finalizer; JSClassGCMark *gc_mark; /* if call != NULL, the object is a function */ JSClassCall *call; } JSClassDef; #define JS_INVALID_CLASS_ID 0 JSClassID JS_NewClassID (JSClassID *pclass_id); /* Returns the class ID if `v` is an object, otherwise returns * JS_INVALID_CLASS_ID. */ JSClassID JS_GetClassID (JSValue v); int JS_NewClass (JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); int JS_IsRegisteredClass (JSRuntime *rt, JSClassID class_id); extern JSClassID js_class_id_alloc; /* ============================================================ Copying GC - No Reference Counting Needed ============================================================ With a copying GC, reference counting is not needed since all live objects are discovered by tracing from roots. These macros make existing DupValue/FreeValue calls into no-ops. ============================================================ */ #define JS_DupValue(ctx, v) (v) #define JS_FreeValue(ctx, v) ((void)0) #define JS_DupValueRT(rt, v) (v) #define JS_FreeValueRT(rt, v) ((void)0) /* value handling */ static inline JSValue JS_NewBool (JSContext *ctx, JS_BOOL val) { return JS_MKVAL (JS_TAG_BOOL, (val != 0)); } static inline JSValue JS_NewInt32 (JSContext *ctx, int32_t val) { return JS_MKVAL (JS_TAG_INT, val); } static inline JSValue JS_NewCatchOffset (JSContext *ctx, int32_t val) { return JS_MKVAL (JS_TAG_CATCH_OFFSET, val); } static inline JSValue JS_NewInt64 (JSContext *ctx, int64_t val) { JSValue v; if (val == (int32_t)val) { v = JS_NewInt32 (ctx, val); } else { v = __JS_NewFloat64 (ctx, val); } return v; } static inline JSValue JS_NewUint32 (JSContext *ctx, uint32_t val) { JSValue v; if (val <= 0x7fffffff) { v = JS_NewInt32 (ctx, val); } else { v = __JS_NewFloat64 (ctx, val); } return v; } static inline JSValue JS_NewFloat64 (JSContext *ctx, double d) { int32_t val; union { double d; uint64_t u; } u, t; if (d >= INT32_MIN && d <= INT32_MAX) { u.d = d; val = (int32_t)d; t.d = val; /* -0 cannot be represented as integer, so we compare the bit representation */ if (u.u == t.u) return JS_MKVAL (JS_TAG_INT, val); } return __JS_NewFloat64 (ctx, d); } static inline JS_BOOL JS_IsNumber (JSValue v) { int tag = JS_VALUE_GET_TAG (v); return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64 (tag); } static inline JS_BOOL JS_IsBool (JSValue v) { return JS_VALUE_GET_TAG (v) == JS_TAG_BOOL; } static inline JS_BOOL JS_IsNull (JSValue v) { return JS_VALUE_GET_TAG (v) == JS_TAG_NULL; } static inline JS_BOOL JS_IsException (JSValue v) { return (JS_VALUE_GET_TAG (v) == JS_TAG_EXCEPTION); } static inline JS_BOOL JS_IsUninitialized (JSValue v) { return (JS_VALUE_GET_TAG (v) == JS_TAG_UNINITIALIZED); } /* Immediate String Helpers */ #define MIST_ASCII_MAX_LEN 7 static inline JS_BOOL MIST_IsImmediateASCII (JSValue v) { return (v & 0x1F) == JS_TAG_STRING_IMM; } static inline int MIST_GetImmediateASCIILen (JSValue v) { return (int)((v >> 5) & 0x7); } static inline int MIST_GetImmediateASCIIChar (JSValue v, int idx) { return (int)((v >> (8 + idx * 8)) & 0xFF); } static inline JSValue MIST_TryNewImmediateASCII (const char *str, size_t len) { if (len > MIST_ASCII_MAX_LEN) return JS_NULL; JSValue v = (JSValue)JS_TAG_STRING_IMM | ((JSValue)len << 5); for (size_t i = 0; i < len; i++) { uint8_t c = (uint8_t)str[i]; if (c >= 0x80) return JS_NULL; v |= (JSValue)c << (8 + i * 8); } return v; } static inline JS_BOOL JS_IsInteger (JSValue v) { return JS_VALUE_GET_TAG (v) == JS_TAG_INT; } static inline JS_BOOL JS_IsObject (JSValue v) { return JS_IsPtr (v); } JS_BOOL JS_IsArray(JSValue v); JS_BOOL JS_IsRecord(JSValue v); JS_BOOL JS_IsFunction(JSValue v); JS_BOOL JS_IsCode(JSValue v); JS_BOOL JS_IsForwarded(JSValue v); JS_BOOL JS_IsFrame(JSValue v); JS_BOOL JS_IsBlob(JSValue v); JS_BOOL JS_IsText(JSValue v); static JS_BOOL JS_IsStone(JSValue v); // Fundamental int JS_GetLength (JSContext *ctx, JSValue obj, int64_t *pres); JSValue JS_Throw (JSContext *ctx, JSValue obj); void JS_SetUncatchableException (JSContext *ctx, JS_BOOL flag); JSValue JS_GetException (JSContext *ctx); JS_BOOL JS_HasException (JSContext *ctx); JS_BOOL JS_IsError (JSContext *ctx, JSValue val); JSValue JS_NewError (JSContext *ctx); JSValue __js_printf_like (2, 3) JS_ThrowSyntaxError (JSContext *ctx, const char *fmt, ...); JSValue __js_printf_like (2, 3) JS_ThrowTypeError (JSContext *ctx, const char *fmt, ...); JSValue __js_printf_like (2, 3) JS_ThrowReferenceError (JSContext *ctx, const char *fmt, ...); JSValue __js_printf_like (2, 3) JS_ThrowRangeError (JSContext *ctx, const char *fmt, ...); JSValue __js_printf_like (2, 3) JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...); JSValue JS_ThrowOutOfMemory (JSContext *ctx); JS_BOOL JS_StrictEq (JSContext *ctx, JSValue op1, JSValue op2); int JS_ToBool (JSContext *ctx, JSValue val); /* return -1 for JS_EXCEPTION */ int JS_ToInt32 (JSContext *ctx, int32_t *pres, JSValue val); static inline int JS_ToUint32 (JSContext *ctx, uint32_t *pres, JSValue val) { return JS_ToInt32 (ctx, (int32_t *)pres, val); } int JS_ToInt64 (JSContext *ctx, int64_t *pres, JSValue val); int JS_ToFloat64 (JSContext *ctx, double *pres, JSValue val); /* return an exception if 'val' is a Number */ JSValue JS_NewStringLen (JSContext *ctx, const char *str1, size_t len1); static inline JSValue JS_NewString (JSContext *ctx, const char *str) { return JS_NewStringLen (ctx, str, strlen (str)); } JSValue JS_ToString (JSContext *ctx, JSValue val); JSValue JS_ToPropertyKey (JSContext *ctx, JSValue val); const char *JS_ToCStringLen2 (JSContext *ctx, size_t *plen, JSValue val1, JS_BOOL cesu8); static inline const char * JS_ToCStringLen (JSContext *ctx, size_t *plen, JSValue val1) { return JS_ToCStringLen2 (ctx, plen, val1, 0); } static inline const char * JS_ToCString (JSContext *ctx, JSValue val1) { return JS_ToCStringLen2 (ctx, NULL, val1, 0); } void JS_FreeCString (JSContext *ctx, const char *ptr); JSValue JS_NewObjectProtoClass (JSContext *ctx, JSValue proto, JSClassID class_id); JSValue JS_NewObjectClass (JSContext *ctx, int class_id); JSValue JS_NewObjectProto (JSContext *ctx, JSValue proto); JSValue JS_NewObject (JSContext *ctx); JSValue JS_NewArray (JSContext *ctx); JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len); /* GC-safe push: takes pointer to array, updates it if array grows */ int JS_ArrayPush (JSContext *ctx, JSValue *arr_ptr, JSValue val); JSValue JS_ArrayPop (JSContext *ctx, JSValue obj); /* Intrinsic array operations - signatures match internal functions */ JSValue JS_Array (JSContext *ctx, JSValue arg0, JSValue arg1, JSValue arg2, JSValue arg3); JSValue JS_ArrayFilter (JSContext *ctx, JSValue arr, JSValue fn); JSValue JS_ArraySort (JSContext *ctx, JSValue arr, JSValue selector); JSValue JS_ArrayFind (JSContext *ctx, JSValue arr, JSValue target_or_fn, JSValue reverse, JSValue from); JSValue JS_ArrFor (JSContext *ctx, JSValue arr, JSValue fn, JSValue reverse, JSValue exit_val); JSValue JS_ArrayReduce (JSContext *ctx, JSValue arr, JSValue fn, JSValue initial, JSValue reverse); /* Cell intrinsic functions - C API wrappers */ /* Core functions */ JSValue JS_CellStone (JSContext *ctx, JSValue val); JSValue JS_CellLength (JSContext *ctx, JSValue val); JSValue JS_CellReverse (JSContext *ctx, JSValue val); JSValue JS_CellProto (JSContext *ctx, JSValue obj); JSValue JS_CellSplat (JSContext *ctx, JSValue val); JSValue JS_CellMeme (JSContext *ctx, JSValue obj, JSValue deep); JSValue JS_CellApply (JSContext *ctx, JSValue fn, JSValue args); JSValue JS_CellCall (JSContext *ctx, JSValue fn, JSValue this_val, JSValue args); JSValue JS_CellModulo (JSContext *ctx, JSValue a, JSValue b); JSValue JS_CellNeg (JSContext *ctx, JSValue val); JSValue JS_CellNot (JSContext *ctx, JSValue val); /* Text functions */ JSValue JS_CellText (JSContext *ctx, JSValue val); JSValue JS_CellLower (JSContext *ctx, JSValue text); JSValue JS_CellUpper (JSContext *ctx, JSValue text); JSValue JS_CellTrim (JSContext *ctx, JSValue text, JSValue chars); JSValue JS_CellCodepoint (JSContext *ctx, JSValue text, JSValue idx); JSValue JS_CellReplace (JSContext *ctx, JSValue text, JSValue pattern, JSValue replacement); JSValue JS_CellSearch (JSContext *ctx, JSValue text, JSValue pattern, JSValue from); JSValue JS_CellExtract (JSContext *ctx, JSValue text, JSValue from, JSValue to); JSValue JS_CellCharacter (JSContext *ctx, JSValue codepoint); /* Number functions */ JSValue JS_CellNumber (JSContext *ctx, JSValue val); JSValue JS_CellAbs (JSContext *ctx, JSValue num); JSValue JS_CellSign (JSContext *ctx, JSValue num); JSValue JS_CellFloor (JSContext *ctx, JSValue num); JSValue JS_CellCeiling (JSContext *ctx, JSValue num); JSValue JS_CellRound (JSContext *ctx, JSValue num); JSValue JS_CellTrunc (JSContext *ctx, JSValue num); JSValue JS_CellWhole (JSContext *ctx, JSValue num); JSValue JS_CellFraction (JSContext *ctx, JSValue num); JSValue JS_CellMin (JSContext *ctx, JSValue a, JSValue b); JSValue JS_CellMax (JSContext *ctx, JSValue a, JSValue b); JSValue JS_CellRemainder (JSContext *ctx, JSValue a, JSValue b); /* Object functions */ JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props); /* Format function */ JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer); /* Helper functions */ JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values); void JS_PrintText (JSContext *ctx, JSValue val); void JS_PrintTextLn (JSContext *ctx, JSValue val); void JS_PrintFormatted (JSContext *ctx, const char *fmt, int count, JSValue *values); JSValue JS_GetProperty (JSContext *ctx, JSValue this_obj, JSValue prop); // For records JSValue JS_GetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop); int JS_SetPropertyStr (JSContext *ctx, JSValue this_obj, const char *prop, JSValue val); int JS_SetProperty (JSContext *ctx, JSValue this_obj, JSValue prop, JSValue val); JSValue JS_GetPrototype (JSContext *ctx, JSValue val); // Must be an array JSValue JS_GetPropertyNumber (JSContext *ctx, JSValue this_obj, int idx); JSValue JS_SetPropertyNumber (JSContext *ctx, JSValue obj, int idx, JSValue val); // Indexed property access (works with arrays and objects) JSValue JS_GetPropertyUint32 (JSContext *ctx, JSValue this_obj, uint32_t idx); int JS_SetPropertyUint32 (JSContext *ctx, JSValue this_obj, uint32_t idx, JSValue val); int JS_SetPropertyInt64 (JSContext *ctx, JSValue this_obj, int64_t idx, JSValue val); /* Get property keys as array of text */ JSValue JS_GetOwnPropertyNames (JSContext *ctx, JSValue obj); JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv); /* Compile source code to bytecode without executing. 'input' must be zero terminated i.e. input[input_len] = '\0'. Returns unlinked bytecode on success, JS_EXCEPTION on error. */ JSValue JS_Compile (JSContext *ctx, const char *input, size_t input_len, const char *filename); /* Link compiled bytecode with environment and execute. env should be stoned record or null. Variables resolve: env first, then global intrinsics. */ JSValue JS_Integrate (JSContext *ctx, JSValue bytecode, JSValue env); void JS_SetOpaque (JSValue obj, void *opaque); void *JS_GetOpaque (JSValue obj, JSClassID class_id); void *JS_GetOpaque2 (JSContext *ctx, JSValue obj, JSClassID class_id); void *JS_GetAnyOpaque (JSValue obj, JSClassID *class_id); /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ JSValue JS_ParseJSON (JSContext *ctx, const char *buf, size_t buf_len, const char *filename); #define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */ JSValue JS_ParseJSON2 (JSContext *ctx, const char *buf, size_t buf_len, const char *filename, int flags); JSValue JS_JSONStringify (JSContext *ctx, JSValue obj, JSValue replacer, JSValue space0); /* return != 0 if the JS code needs to be interrupted */ typedef int JSInterruptHandler (JSRuntime *rt, void *opaque); void JS_SetInterruptHandler (JSRuntime *rt, JSInterruptHandler *cb, void *opaque); /* select which debug info is stripped from the compiled code */ #define JS_STRIP_SOURCE (1 << 0) /* strip source code */ #define JS_STRIP_DEBUG \ (1 << 1) /* strip all debug info including source code */ void JS_SetStripInfo (JSRuntime *rt, int flags); int JS_GetStripInfo (JSRuntime *rt); /* Object Writer/Reader (currently only used to handle precompiled code) */ #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_WRITE_OBJ_REFERENCE \ (1 << 3) /* allow object references to \ encode arbitrary object \ graph */ uint8_t *JS_WriteObject (JSContext *ctx, size_t *psize, JSValue obj, int flags); uint8_t *JS_WriteObject2 (JSContext *ctx, size_t *psize, JSValue obj, int flags, uint8_t ***psab_tab, size_t *psab_tab_len); #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ JSValue JS_ReadObject (JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); /* Dump bytecode of a compiled function (for debugging) */ void JS_DumpFunctionBytecode (JSContext *ctx, JSValue func_val); /* C function definition */ typedef enum JSCFunctionEnum { JS_CFUNC_generic, JS_CFUNC_generic_magic, JS_CFUNC_f_f, JS_CFUNC_f_f_f, /* Fixed-arity fast paths - no argc/argv overhead */ JS_CFUNC_0, /* JSValue f(ctx, this_val) */ JS_CFUNC_1, /* JSValue f(ctx, this_val, arg0) */ JS_CFUNC_2, /* JSValue f(ctx, this_val, arg0, arg1) */ JS_CFUNC_3, /* JSValue f(ctx, this_val, arg0, arg1, arg2) */ JS_CFUNC_4, /* Pure functions (no this_val) - for global utility functions */ JS_CFUNC_PURE, /* JSValue f(ctx, argc, argv) - generic pure */ JS_CFUNC_PURE_0, /* JSValue f(ctx) */ JS_CFUNC_PURE_1, /* JSValue f(ctx, arg0) */ JS_CFUNC_PURE_2, /* JSValue f(ctx, arg0, arg1) */ JS_CFUNC_PURE_3, /* JSValue f(ctx, arg0, arg1, arg2) */ JS_CFUNC_PURE_4 /* JSValue f(ctx, arg0, arg1, arg2, arg3) */ } JSCFunctionEnum; /* Fixed-arity C function types for fast paths */ typedef JSValue JSCFunction0 (JSContext *ctx, JSValue this_val); typedef JSValue JSCFunction1 (JSContext *ctx, JSValue this_val, JSValue arg0); typedef JSValue JSCFunction2 (JSContext *ctx, JSValue this_val, JSValue arg0, JSValue arg1); typedef JSValue JSCFunction3 (JSContext *ctx, JSValue this_val, JSValue arg0, JSValue arg1, JSValue arg2); typedef JSValue JSCFunction4 (JSContext *ctx, JSValue this_val, JSValue arg0, JSValue arg1, JSValue arg2, JSValue arg3); /* Pure function types (no this_val) */ typedef JSValue JSCFunctionPure (JSContext *ctx, int argc, JSValue *argv); typedef JSValue JSCFunctionPure0 (JSContext *ctx); typedef JSValue JSCFunctionPure1 (JSContext *ctx, JSValue arg0); typedef JSValue JSCFunctionPure2 (JSContext *ctx, JSValue arg0, JSValue arg1); typedef JSValue JSCFunctionPure3 (JSContext *ctx, JSValue arg0, JSValue arg1, JSValue arg2); typedef JSValue JSCFunctionPure4 (JSContext *ctx, JSValue arg0, JSValue arg1, JSValue arg2, JSValue arg3); typedef union JSCFunctionType { JSCFunction *generic; JSValue (*generic_magic) (JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic); double (*f_f) (double); double (*f_f_f) (double, double); /* Fixed-arity fast paths */ JSCFunction0 *f0; JSCFunction1 *f1; JSCFunction2 *f2; JSCFunction3 *f3; JSCFunction4 *f4; /* Pure function pointers */ JSCFunctionPure *pure; JSCFunctionPure0 *pure0; JSCFunctionPure1 *pure1; JSCFunctionPure2 *pure2; JSCFunctionPure3 *pure3; JSCFunctionPure4 *pure4; } JSCFunctionType; JSValue JS_NewCFunction2 (JSContext *ctx, JSCFunction *func, const char *name, int length, JSCFunctionEnum cproto, int magic); static inline JSValue JS_NewCFunction (JSContext *ctx, JSCFunction *func, const char *name, int length) { return JS_NewCFunction2 (ctx, func, name, length, JS_CFUNC_generic, 0); } static inline JSValue JS_NewCFunctionMagic (JSContext *ctx, JSCFunctionMagic *func, const char *name, int length, JSCFunctionEnum cproto, int magic) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, length, cproto, magic); } /* Fixed-arity fast path constructors */ static inline JSValue JS_NewCFuncFixed0 (JSContext *ctx, JSCFunction0 *func, const char *name) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 0, JS_CFUNC_0, 0); } static inline JSValue JS_NewCFuncFixed1 (JSContext *ctx, JSCFunction1 *func, const char *name) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 1, JS_CFUNC_1, 0); } static inline JSValue JS_NewCFuncFixed2 (JSContext *ctx, JSCFunction2 *func, const char *name) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 2, JS_CFUNC_2, 0); } static inline JSValue JS_NewCFuncFixed3 (JSContext *ctx, JSCFunction3 *func, const char *name) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 3, JS_CFUNC_3, 0); } static inline JSValue JS_NewCFuncFixed4 (JSContext *ctx, JSCFunction4 *func, const char *name) { return JS_NewCFunction2 (ctx, (JSCFunction *)func, name, 4, JS_CFUNC_4, 0); } /* C property definition */ typedef struct JSCFunctionListEntry { const char *name; uint8_t prop_flags; uint8_t def_type; int16_t magic; union { struct { uint8_t length; /* XXX: should move outside union */ uint8_t cproto; /* XXX: should move outside union */ JSCFunctionType cfunc; } func; struct { const char *name; int base; } alias; struct { const struct JSCFunctionListEntry *tab; int len; } prop_list; const char *str; int32_t i32; int64_t i64; double f64; } u; } JSCFunctionListEntry; #define JS_DEF_CFUNC 0 #define JS_DEF_PROP_STRING 3 #define JS_DEF_PROP_INT32 4 #define JS_DEF_PROP_INT64 5 #define JS_DEF_PROP_DOUBLE 6 #define JS_DEF_PROP_UNDEFINED 7 #define JS_DEF_OBJECT 8 #define JS_DEF_ALIAS 9 /* Note: c++ does not like nested designators */ #define JS_CFUNC_DEF(name, length, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { length, JS_CFUNC_generic, { .generic = func1 } } } \ } #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) \ { \ name, 0, JS_DEF_CFUNC, magic, .u = { \ .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } \ } \ } #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { length, JS_CFUNC_##cproto, { .cproto = func1 } } } \ } /* Fixed-arity fast path macros */ #define JS_CFUNC0_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 0, JS_CFUNC_0, { .f0 = func1 } } } \ } #define JS_CFUNC1_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 1, JS_CFUNC_1, { .f1 = func1 } } } \ } #define JS_CFUNC2_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 2, JS_CFUNC_2, { .f2 = func1 } } } \ } #define JS_CFUNC3_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 3, JS_CFUNC_3, { .f3 = func1 } } } \ } /* Pure function (no this_val) macros */ #define JS_CFUNC_PURE_DEF(name, length, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { length, JS_CFUNC_PURE, { .pure = func1 } } } \ } #define JS_CFUNC_PURE0_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 0, JS_CFUNC_PURE_0, { .pure0 = func1 } } } \ } #define JS_CFUNC_PURE1_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 1, JS_CFUNC_PURE_1, { .pure1 = func1 } } } \ } #define JS_CFUNC_PURE2_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 2, JS_CFUNC_PURE_2, { .pure2 = func1 } } } \ } #define JS_CFUNC_PURE3_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 3, JS_CFUNC_PURE_3, { .pure3 = func1 } } } \ } #define JS_CFUNC_PURE4_DEF(name, func1) \ { \ name, 0, JS_DEF_CFUNC, 0, \ .u \ = {.func = { 4, JS_CFUNC_PURE_4, { .pure4 = func1 } } } \ } #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) \ { \ name, 0, JS_DEF_CFUNC, magic, .u = { \ .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } \ } \ } #define JS_PROP_STRING_DEF(name, cstr, prop_flags) \ { \ name, prop_flags, JS_DEF_PROP_STRING, 0, .u = {.str = cstr } \ } #define JS_PROP_INT32_DEF(name, val, prop_flags) \ { \ name, prop_flags, JS_DEF_PROP_INT32, 0, .u = {.i32 = val } \ } #define JS_PROP_INT64_DEF(name, val, prop_flags) \ { \ name, prop_flags, JS_DEF_PROP_INT64, 0, .u = {.i64 = val } \ } #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) \ { \ name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = {.f64 = val } \ } #define JS_PROP_UNDEFINED_DEF(name, prop_flags) \ { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } #define JS_OBJECT_DEF(name, tab, len, prop_flags) \ { \ name, prop_flags, JS_DEF_OBJECT, 0, .u = {.prop_list = { tab, len } } \ } #define JS_ALIAS_DEF(name, from) \ { \ name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ .u \ = {.alias = { from, -1 } } \ } #define JS_ALIAS_BASE_DEF(name, from, base) \ { \ name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, \ .u \ = {.alias = { from, base } } \ } int JS_SetPropertyFunctionList (JSContext *ctx, JSValue obj, const JSCFunctionListEntry *tab, int len); /* debug value output */ typedef struct { JS_BOOL show_hidden : 8; /* only show enumerable properties */ JS_BOOL raw_dump : 8; /* avoid doing autoinit and avoid any malloc() call (for internal use) */ uint32_t max_depth; /* recurse up to this depth, 0 = no limit */ uint32_t max_string_length; /* print no more than this length for strings, 0 = no limit */ uint32_t max_item_count; /* print no more than this count for arrays or objects, 0 = no limit */ } JSPrintValueOptions; typedef void JSPrintValueWrite (void *opaque, const char *buf, size_t len); void JS_PrintValueSetDefaultOptions (JSPrintValueOptions *options); void JS_PrintValueRT (JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque, JSValue val, const JSPrintValueOptions *options); void JS_PrintValue (JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque, JSValue val, const JSPrintValueOptions *options); typedef struct js_debug { char name[64]; char filename[96]; int unique; int line; int param_n; int closure_n; int vararg; const char *what; const uint8_t *source; int srclen; } js_debug; void js_debug_info (JSContext *js, JSValue fn, js_debug *dbg); typedef void (*js_hook) (JSContext *, int type, js_debug *dbg, void *user); #define JS_HOOK_CALL 1 #define JS_HOOK_RET 2 #define JS_HOOK_CYCLE 4 #define JS_HOOK_GC 8 void js_debug_sethook (JSContext *ctx, js_hook, int type, void *user); uint32_t js_debugger_stack_depth (JSContext *ctx); JSValue js_debugger_backtrace_fns (JSContext *ctx, const uint8_t *cur_pc); JSValue js_debugger_closure_variables (JSContext *ctx, JSValue fn); JSValue js_debugger_local_variables (JSContext *ctx, int stack_index); void js_debugger_set_closure_variable (JSContext *js, JSValue fn, JSValue var_name, JSValue val); JSValue js_debugger_build_backtrace (JSContext *ctx, const uint8_t *cur_pc); JSValue js_debugger_fn_info (JSContext *ctx, JSValue fn); JSValue js_debugger_fn_bytecode (JSContext *js, JSValue fn); void *js_debugger_val_address (JSContext *js, JSValue val); /* Memory allocation functions (bump allocator) */ void *js_malloc (JSContext *ctx, size_t size); void *js_mallocz (JSContext *ctx, size_t size); void *js_realloc (JSContext *ctx, void *ptr, size_t size); void js_free (JSContext *ctx, void *ptr); char *js_strdup (JSContext *ctx, const char *str); /* Runtime-level memory functions */ void *js_malloc_rt (size_t size); void *js_mallocz_rt (size_t size); void js_free_rt (void *ptr); /* ============================================================================ Context-Neutral Module Format (CellModule) ============================================================================ */ /* Capture descriptor - what a nested function closes over */ typedef enum { CAP_FROM_PARENT_LOCAL = 1, /* capture local from parent function */ CAP_FROM_PARENT_UPVALUE = 2 /* forward upvalue from parent's upvalues */ } CellCapKind; typedef struct CellCapDesc { uint8_t kind; /* CAP_FROM_PARENT_LOCAL or CAP_FROM_PARENT_UPVALUE */ uint16_t index; /* local index in parent, or upvalue index in parent */ } CellCapDesc; /* External relocation - for integrate-time patching */ typedef enum { EXT_GET = 1, /* OP_get_var -> OP_get_env_slot or OP_get_global_slot */ EXT_SET = 2 /* OP_put_var -> OP_set_env_slot or OP_set_global_slot */ } CellExtKind; typedef struct CellExternalReloc { uint32_t pc_offset; /* where operand lives in bytecode */ uint32_t name_sid; /* string id of the external name */ uint8_t kind; /* EXT_GET or EXT_SET */ } CellExternalReloc; /* Constant types in cpool */ typedef enum { CELL_CONST_NULL = 0, CELL_CONST_INT = 1, CELL_CONST_FLOAT = 2, CELL_CONST_STRING = 3, /* string_sid into module string table */ CELL_CONST_UNIT = 4 /* unit_id for nested function */ } CellConstType; typedef struct CellConst { uint8_t type; /* CellConstType */ union { int32_t i32; double f64; uint32_t string_sid; uint32_t unit_id; }; } CellConst; /* Per-unit structure (context-neutral, flattened) */ typedef struct CellUnit { /* Constant pool */ uint32_t const_count; CellConst *constants; /* Bytecode */ uint32_t bytecode_len; uint8_t *bytecode; /* Stack requirements */ uint16_t arg_count; uint16_t var_count; uint16_t stack_size; /* Upvalue (capture) descriptors */ uint16_t upvalue_count; CellCapDesc *upvalues; /* External relocations */ uint32_t external_count; CellExternalReloc *externals; /* Debug info (optional) */ uint32_t pc2line_len; uint8_t *pc2line; uint32_t name_sid; /* unit name for stack traces */ } CellUnit; /* Module-level structure (context-neutral) */ #define CELL_MODULE_MAGIC 0x4C4C4543 /* "CELL" */ #define CELL_MODULE_VERSION 1 typedef struct CellModule { uint32_t magic; /* CELL_MODULE_MAGIC */ uint8_t version; /* CELL_MODULE_VERSION */ uint8_t flags; /* Shared string table (module-global) */ uint32_t string_count; uint32_t string_data_size; uint8_t *string_data; /* concatenated UTF-8 strings */ uint32_t *string_offsets; /* offset for each string */ /* Unit table (entry 0 is the main/entry unit) */ uint32_t unit_count; CellUnit *units; /* Debug: source stored once at module level */ uint32_t source_len; char *source; } CellModule; /* Free a CellModule and all its contents */ void cell_module_free (CellModule *mod); /* Write a CellModule to a byte buffer. Returns allocated buffer (caller must free with pjs_free), or NULL on error. */ uint8_t *cell_module_write (CellModule *mod, size_t *out_len); /* Read a CellModule from a byte buffer. Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */ CellModule *cell_module_read (const uint8_t *buf, size_t buf_len); /* Convert compiled JSFunctionBytecode to CellModule. Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */ CellModule *cell_module_from_bytecode (JSContext *ctx, JSFunctionBytecode *main_func); /* Compile source code directly to CellModule. Returns allocated CellModule (caller must free with cell_module_free), or NULL on error. */ CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename); /* Parse source code and return AST as JSON string. Returns malloc'd JSON string (caller must free), or NULL on error. No JSContext needed — pure string transformation. */ char *JS_AST (const char *source, size_t len, const char *filename); /* Tokenize source code and return token array as JSON string. Returns malloc'd JSON string (caller must free), or NULL on error. No JSContext needed — pure string transformation. */ char *JS_Tokenize (const char *source, size_t len, const char *filename); /* Compiled bytecode (context-free, serializable) */ typedef struct MachCode MachCode; /* Compile AST JSON to context-free MachCode. Returns MachCode* (caller must free with JS_FreeMachCode), or NULL on error. */ MachCode *JS_CompileMach(const char *ast_json); /* Free a compiled MachCode tree. */ void JS_FreeMachCode(MachCode *mc); /* Load compiled MachCode into a JSContext, materializing JSValues. Returns JSCodeRegister* linked and ready for execution. */ struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env); /* Dump MACH bytecode to stdout for debugging. Takes AST JSON. Internally compiles, loads, and dumps binary bytecode. */ void JS_DumpMach (JSContext *ctx, const char *ast_json, JSValue env); /* Compile and execute MACH bytecode. Takes AST JSON. Internally compiles, loads, and executes. Returns result of execution, or JS_EXCEPTION on error. */ JSValue JS_RunMach (JSContext *ctx, const char *ast_json, JSValue env); /* Compile AST JSON to MCODE JSON (string-based IR). Returns malloc'd JSON string, or NULL on error. Caller must free. No JSContext needed — pure string transformation. */ char *JS_Mcode (const char *ast_json); /* Parse and execute MCODE JSON directly via the MCODE interpreter. Returns result of execution, or JS_EXCEPTION on error. */ JSValue JS_CallMcode (JSContext *ctx, const char *mcode_json); /* Get stack trace as cJSON array of frame objects. Returns NULL if no register VM frame is active. Caller must call cJSON_Delete() on the result. */ struct cJSON *JS_GetStack (JSContext *ctx); /* Integrate a CellModule with an environment and execute. Returns callable function value, or JS_EXCEPTION on error. */ JSValue cell_module_integrate (JSContext *ctx, CellModule *mod, JSValue env); #undef js_unlikely #undef inline #ifdef __cplusplus } /* extern "C" { */ #endif #endif /* QUICKJS_H */