Files
cell/source/cell.c

893 lines
25 KiB
C

#ifdef _WIN32
#include <windows.h>
#endif
#include "wota.h"
#define STB_DS_IMPLEMENTATION
#include "stb_ds.h"
#include "cell.h"
#include "cell_internal.h"
#include "cJSON.h"
#define ENGINE "internal/engine.cm"
#define CELL_SHOP_DIR ".cell"
#define CELL_CORE_DIR "packages/core"
#include <math.h>
#include <signal.h>
#include <unistd.h>
#include <sys/stat.h>
/* Test suite declarations */
int run_c_test_suite(JSContext *ctx);
static int run_test_suite(size_t heap_size);
cell_rt *root_cell = NULL;
static char *core_path = NULL;
// Get the home directory
static const char* get_home_dir(void) {
const char *home = getenv("HOME");
if (!home) {
home = getenv("USERPROFILE"); // Windows fallback
}
return home;
}
// Find and verify the cell shop at ~/.cell
int find_cell_shop(void)
{
const char *home = get_home_dir();
if (!home) {
printf("ERROR: Could not determine home directory. Set HOME environment variable.\n");
return 0;
}
// Build path to ~/.cell/core
size_t path_len = strlen(home) + strlen("/" CELL_SHOP_DIR "/" CELL_CORE_DIR) + 1;
core_path = malloc(path_len);
if (!core_path) {
printf("ERROR: Could not allocate memory for core path\n");
return 0;
}
snprintf(core_path, path_len, "%s/" CELL_SHOP_DIR "/" CELL_CORE_DIR, home);
// Check if the core directory exists
struct stat st;
if (stat(core_path, &st) != 0 || !S_ISDIR(st.st_mode)) {
printf("ERROR: Cell shop not found at %s/" CELL_SHOP_DIR "\n", home);
printf("Run 'cell install' to set up the cell environment.\n");
free(core_path);
core_path = NULL;
return 0;
}
return 1;
}
// Load a file from the core directory
static char* load_core_file(const char *filename, size_t *out_size) {
if (!core_path) return NULL;
size_t path_len = strlen(core_path) + 1 + strlen(filename) + 1;
char *full_path = malloc(path_len);
if (!full_path) return NULL;
snprintf(full_path, path_len, "%s/%s", core_path, filename);
FILE *fh = fopen(full_path, "rb");
free(full_path);
if (!fh) return NULL;
fseek(fh, 0, SEEK_END);
long file_size = ftell(fh);
fseek(fh, 0, SEEK_SET);
char *data = malloc(file_size + 1);
if (!data) {
fclose(fh);
return NULL;
}
if (fread(data, 1, file_size, fh) != (size_t)file_size) {
free(data);
fclose(fh);
return NULL;
}
fclose(fh);
data[file_size] = 0;
if (out_size) *out_size = file_size;
return data;
}
static int print_tree_errors(cJSON *root) {
if (!root) return 0;
cJSON *errors = cJSON_GetObjectItemCaseSensitive(root, "errors");
if (!cJSON_IsArray(errors) || cJSON_GetArraySize(errors) == 0)
return 0;
const char *filename = "<unknown>";
cJSON *fname = cJSON_GetObjectItemCaseSensitive(root, "filename");
if (cJSON_IsString(fname))
filename = fname->valuestring;
cJSON *e;
cJSON_ArrayForEach(e, errors) {
const char *msg = cJSON_GetStringValue(
cJSON_GetObjectItemCaseSensitive(e, "message"));
cJSON *line = cJSON_GetObjectItemCaseSensitive(e, "line");
cJSON *col = cJSON_GetObjectItemCaseSensitive(e, "column");
if (msg && cJSON_IsNumber(line) && cJSON_IsNumber(col))
fprintf(stderr, "%s:%d:%d: error: %s\n",
filename, (int)line->valuedouble, (int)col->valuedouble, msg);
else if (msg)
fprintf(stderr, "%s: error: %s\n", filename, msg);
}
return 1;
}
static int print_json_errors(const char *json) {
if (!json) return 0;
cJSON *root = cJSON_Parse(json);
if (!root) return 0;
int result = print_tree_errors(root);
cJSON_Delete(root);
return result;
}
// Get the core path for use by scripts
const char* cell_get_core_path(void) {
return core_path;
}
void actor_disrupt(cell_rt *crt)
{
crt->disrupt = 1;
if (crt->state != ACTOR_RUNNING)
actor_free(crt);
}
JSValue js_os_use(JSContext *js);
JSValue js_math_use(JSContext *js);
JSValue js_json_use(JSContext *js);
JSValue js_nota_use(JSContext *js);
JSValue js_wota_use(JSContext *js);
void script_startup(cell_rt *prt)
{
JSRuntime *rt = JS_NewRuntime();
JS_SetInterruptHandler(rt, (JSInterruptHandler *)actor_interrupt_cb, prt);
JSContext *js = JS_NewContext(rt);
JS_SetContextOpaque(js, prt);
prt->context = js;
cell_rt *crt = JS_GetContextOpaque(js);
JS_FreeValue(js, js_blob_use(js));
// Load and compile engine.cm
size_t engine_size;
char *data = load_core_file(ENGINE, &engine_size);
if (!data) {
printf("ERROR: Could not load %s from %s!\n", ENGINE, core_path);
return;
}
JSValue bytecode = JS_Compile(js, data, engine_size, ENGINE);
free(data);
if (JS_IsException(bytecode)) {
uncaught_exception(js, bytecode);
return;
}
// Create hidden environment
JSValue hidden_env = JS_NewObject(js);
JS_SetPropertyStr(js, hidden_env, "os", js_os_use(js));
JS_SetPropertyStr(js, hidden_env, "json", js_json_use(js));
JS_SetPropertyStr(js, hidden_env, "nota", js_nota_use(js));
JS_SetPropertyStr(js, hidden_env, "wota", js_wota_use(js));
crt->actor_sym = JS_NewObject(js);
JS_SetPropertyStr(js, hidden_env, "actorsym", JS_DupValue(js, crt->actor_sym));
// Always set init (even if null)
if (crt->init_wota) {
JS_SetPropertyStr(js, hidden_env, "init", wota2value(js, crt->init_wota));
free(crt->init_wota);
crt->init_wota = NULL;
} else {
JS_SetPropertyStr(js, hidden_env, "init", JS_NULL);
}
if (core_path) {
JS_SetPropertyStr(js, hidden_env, "core_path", JS_NewString(js, core_path));
}
// Stone the environment
hidden_env = JS_Stone(js, hidden_env);
// Integrate and run
crt->state = ACTOR_RUNNING;
JSValue v = JS_Integrate(js, bytecode, hidden_env);
uncaught_exception(js, v);
crt->state = ACTOR_IDLE;
set_actor_state(crt);
}
static void signal_handler(int sig)
{
const char *str = NULL;
#ifndef TARGET_PLAYDATE
switch (sig) {
case SIGABRT: str = "SIGABRT"; break;
case SIGFPE: str = "SIGFPE"; break;
case SIGILL: str = "SIGILL"; break;
case SIGINT: str = "SIGINT"; break;
case SIGSEGV: str = "SIGSEGV"; break;
case SIGTERM: str = "SIGTERM"; break;
}
#endif
if (!str) return;
exit_handler();
}
/* Run the C test suite with minimal runtime setup */
static int run_test_suite(size_t heap_size)
{
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
printf("Failed to create JS runtime\n");
return 1;
}
JSContext *ctx = JS_NewContextWithHeapSize(rt, heap_size);
if (!ctx) {
printf("Failed to create JS context\n");
JS_FreeRuntime(rt);
return 1;
}
int result = run_c_test_suite(ctx);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return result;
}
/* Run an immediate script string */
static int run_eval(const char *script_or_file, int print_bytecode, int use_bootstrap_env)
{
if (!find_cell_shop()) return 1;
/* Check if argument is a file path */
struct stat st;
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
/* It's a file, read its contents */
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
/* Treat as inline script */
script = (char *)script_or_file;
}
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
printf("Failed to create JS runtime\n");
free(allocated_script);
return 1;
}
JSContext *ctx = JS_NewContext(rt);
if (!ctx) {
printf("Failed to create JS context\n");
JS_FreeRuntime(rt);
free(allocated_script);
return 1;
}
int result = 0;
JSGCRef bytecode_ref;
JS_PushGCRef(ctx, &bytecode_ref);
bytecode_ref.val = JS_Compile(ctx, script, strlen(script), filename);
if (JS_IsException(bytecode_ref.val)) {
uncaught_exception(ctx, bytecode_ref.val);
JS_PopGCRef(ctx, &bytecode_ref);
result = 1;
} else {
if (print_bytecode) {
printf("=== Compiled Bytecode ===\n");
JS_DumpFunctionBytecode(ctx, bytecode_ref.val);
}
JSValue env = JS_NULL;
if (use_bootstrap_env) {
JSGCRef env_ref, json_ref, nota_ref, wota_ref;
JS_PushGCRef(ctx, &env_ref);
JS_PushGCRef(ctx, &json_ref);
JS_PushGCRef(ctx, &nota_ref);
JS_PushGCRef(ctx, &wota_ref);
env_ref.val = JS_NewObject(ctx);
/* Create modules with GC rooting, then stone them */
json_ref.val = js_json_use(ctx);
nota_ref.val = js_nota_use(ctx);
wota_ref.val = js_wota_use(ctx);
JS_SetPropertyStr(ctx, env_ref.val, "json", JS_Stone(ctx, json_ref.val));
JS_SetPropertyStr(ctx, env_ref.val, "nota", JS_Stone(ctx, nota_ref.val));
JS_SetPropertyStr(ctx, env_ref.val, "wota", JS_Stone(ctx, wota_ref.val));
env = JS_Stone(ctx, env_ref.val);
JS_PopGCRef(ctx, &wota_ref);
JS_PopGCRef(ctx, &nota_ref);
JS_PopGCRef(ctx, &json_ref);
JS_PopGCRef(ctx, &env_ref);
}
JSValue v = JS_Integrate(ctx, bytecode_ref.val, env);
JS_PopGCRef(ctx, &bytecode_ref);
if (JS_IsException(v)) {
uncaught_exception(ctx, v);
result = 1;
} else {
JS_FreeValue(ctx, v);
}
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
free(allocated_script);
return result;
}
int cell_init(int argc, char **argv)
{
/* Check for --test flag to run C test suite */
if (argc >= 2 && strcmp(argv[1], "--test") == 0) {
size_t heap_size = 64 * 1024; /* 64KB default */
if (argc >= 3) {
heap_size = strtoull(argv[2], NULL, 0);
/* Round up to power of 2 for buddy allocator */
size_t p = 1;
while (p < heap_size) p <<= 1;
heap_size = p;
}
return run_test_suite(heap_size);
}
/* Check for --ast flag to output AST JSON */
if (argc >= 3 && strcmp(argv[1], "--ast") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
cJSON *ast = JS_ASTTree(script, strlen(script), filename);
if (ast) {
int has_errors = print_tree_errors(ast);
char *pretty = cJSON_Print(ast);
cJSON_Delete(ast);
printf("%s\n", pretty);
free(pretty);
free(allocated_script);
return has_errors ? 1 : 0;
} else {
printf("Failed to parse AST\n");
free(allocated_script);
return 1;
}
}
/* Check for --tokenize flag to output token array JSON */
if (argc >= 3 && strcmp(argv[1], "--tokenize") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
char *json = JS_Tokenize(script, strlen(script), filename);
if (json) {
int has_errors = print_json_errors(json);
cJSON *root = cJSON_Parse(json);
free(json);
if (root) {
char *pretty = cJSON_Print(root);
cJSON_Delete(root);
printf("%s\n", pretty);
free(pretty);
}
free(allocated_script);
return has_errors ? 1 : 0;
} else {
printf("Failed to tokenize\n");
free(allocated_script);
return 1;
}
}
/* Check for --mcode flag to output MCODE JSON IR */
if (argc >= 3 && strcmp(argv[1], "--mcode") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
char *ast_json = JS_AST(script, strlen(script), filename);
if (!ast_json) {
printf("Failed to parse AST\n");
free(allocated_script);
return 1;
}
if (print_json_errors(ast_json)) {
free(ast_json);
free(allocated_script);
return 1;
}
char *mcode_json = JS_Mcode(ast_json);
free(ast_json);
if (!mcode_json) {
printf("Failed to generate MCODE\n");
free(allocated_script);
return 1;
}
cJSON *root = cJSON_Parse(mcode_json);
free(mcode_json);
if (root) {
char *pretty = cJSON_Print(root);
cJSON_Delete(root);
printf("%s\n", pretty);
free(pretty);
}
free(allocated_script);
return 0;
}
/* Check for --run-mcode flag to execute via MCODE interpreter */
if (argc >= 3 && strcmp(argv[1], "--run-mcode") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) { printf("Failed to open file: %s\n", script_or_file); return 1; }
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) { fclose(f); printf("Failed to allocate memory\n"); return 1; }
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
char *ast_json = JS_AST(script, strlen(script), filename);
if (!ast_json) {
printf("Failed to parse AST\n");
free(allocated_script);
return 1;
}
if (print_json_errors(ast_json)) {
free(ast_json); free(allocated_script);
return 1;
}
char *mcode_json = JS_Mcode(ast_json);
free(ast_json);
if (!mcode_json) {
printf("Failed to generate MCODE\n");
free(allocated_script);
return 1;
}
if (print_json_errors(mcode_json)) {
free(mcode_json); free(allocated_script);
return 1;
}
/* Use a larger heap context for execution */
JSRuntime *rt = JS_NewRuntime();
if (!rt) { printf("Failed to create JS runtime\n"); free(mcode_json); free(allocated_script); return 1; }
JSContext *ctx = JS_NewContextWithHeapSize(rt, 64 * 1024);
if (!ctx) { printf("Failed to create execution context\n"); free(mcode_json); JS_FreeRuntime(rt); free(allocated_script); return 1; }
JSValue result = JS_CallMcode(ctx, mcode_json);
free(mcode_json);
if (JS_IsException(result)) {
JSValue exc = JS_GetException(ctx);
const char *str = JS_ToCString(ctx, exc);
if (str) { printf("Error: %s\n", str); JS_FreeCString(ctx, str); }
cJSON *stack = JS_GetStack(ctx);
if (stack) {
int n = cJSON_GetArraySize(stack);
for (int i = 0; i < n; i++) {
cJSON *fr = cJSON_GetArrayItem(stack, i);
const char *fn = cJSON_GetStringValue(cJSON_GetObjectItem(fr, "function"));
const char *file = cJSON_GetStringValue(cJSON_GetObjectItem(fr, "file"));
int line = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(fr, "line"));
int col = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(fr, "column"));
printf(" at %s (%s:%d:%d)\n", fn ? fn : "<anonymous>", file ? file : "<unknown>", line, col);
}
cJSON_Delete(stack);
}
JS_FreeValue(ctx, exc);
} else if (!JS_IsNull(result)) {
const char *str = JS_ToCString(ctx, result);
if (str) { printf("%s\n", str); JS_FreeCString(ctx, str); }
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
free(allocated_script);
return JS_IsException(result) ? 1 : 0;
}
/* Check for --mach flag to dump MACH bytecode */
if (argc >= 3 && strcmp(argv[1], "--mach") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
cJSON *ast = JS_ASTTree(script, strlen(script), filename);
if (!ast) {
printf("Failed to parse AST\n");
free(allocated_script);
return 1;
}
if (print_tree_errors(ast)) {
cJSON_Delete(ast);
free(allocated_script);
return 1;
}
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
printf("Failed to create JS runtime\n");
cJSON_Delete(ast); free(allocated_script);
return 1;
}
JSContext *ctx = JS_NewContext(rt);
if (!ctx) {
printf("Failed to create JS context\n");
cJSON_Delete(ast); JS_FreeRuntime(rt); free(allocated_script);
return 1;
}
JS_DumpMachTree(ctx, ast, JS_NULL);
cJSON_Delete(ast);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
free(allocated_script);
return 0;
}
/* Check for --mach-run flag to compile and run through MACH VM */
if (argc >= 3 && strcmp(argv[1], "--mach-run") == 0) {
const char *script_or_file = argv[2];
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
struct stat st;
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
script = (char *)script_or_file;
}
cJSON *ast = JS_ASTTree(script, strlen(script), filename);
if (!ast) {
printf("Failed to parse AST\n");
free(allocated_script);
return 1;
}
if (print_tree_errors(ast)) {
cJSON_Delete(ast);
free(allocated_script);
return 1;
}
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
printf("Failed to create JS runtime\n");
cJSON_Delete(ast); free(allocated_script);
return 1;
}
JSContext *ctx = JS_NewContext(rt);
if (!ctx) {
printf("Failed to create JS context\n");
cJSON_Delete(ast); JS_FreeRuntime(rt); free(allocated_script);
return 1;
}
JSValue result = JS_RunMachTree(ctx, ast, JS_NULL);
cJSON_Delete(ast);
int exit_code = 0;
if (JS_IsException(result)) {
JSValue exc = JS_GetException(ctx);
const char *err_str = JS_ToCString(ctx, exc);
if (err_str) {
printf("Error: %s\n", err_str);
JS_FreeCString(ctx, err_str);
}
cJSON *stack = JS_GetStack(ctx);
if (stack) {
int n = cJSON_GetArraySize(stack);
for (int i = 0; i < n; i++) {
cJSON *fr = cJSON_GetArrayItem(stack, i);
const char *fn = cJSON_GetStringValue(cJSON_GetObjectItem(fr, "function"));
const char *file = cJSON_GetStringValue(cJSON_GetObjectItem(fr, "file"));
int line = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(fr, "line"));
int col = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(fr, "column"));
printf(" at %s (%s:%d:%d)\n", fn ? fn : "<anonymous>", file ? file : "<unknown>", line, col);
}
cJSON_Delete(stack);
}
JS_FreeValue(ctx, exc);
exit_code = 1;
} else if (!JS_IsNull(result)) {
const char *str = JS_ToCString(ctx, result);
if (str) {
printf("%s\n", str);
JS_FreeCString(ctx, str);
}
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
free(allocated_script);
return exit_code;
}
/* Check for -e or --eval flag to run immediate script */
/* Also check for -p flag to print bytecode */
/* -s / --serializers flag provides json, nota, wota in env */
if (argc >= 3 && (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "--eval") == 0)) {
return run_eval(argv[2], 0, 0);
}
if (argc >= 3 && (strcmp(argv[1], "-p") == 0 || strcmp(argv[1], "--print-bytecode") == 0)) {
return run_eval(argv[2], 1, 0);
}
if (argc >= 3 && (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--serializers") == 0)) {
return run_eval(argv[2], 0, 1);
}
int script_start = 1;
/* Find the cell shop at ~/.cell */
int found = find_cell_shop();
if (!found) {
return 1;
}
/* Create the initial actor from the command line */
int actor_argc = argc - script_start;
char **actor_argv = argv + script_start;
WotaBuffer startwota;
wota_buffer_init(&startwota, 5);
wota_write_record(&startwota, 2);
wota_write_text(&startwota, "program");
wota_write_text(&startwota, actor_argv[0]);
wota_write_text(&startwota, "arg");
wota_write_array(&startwota, actor_argc - 1);
for (int i = 1; i < actor_argc; i++)
wota_write_text(&startwota, actor_argv[i]);
/* Initialize synchronization primitives */
actor_initialize();
root_cell = create_actor(startwota.data);
#ifndef TARGET_PLAYDATE
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
signal(SIGSEGV, signal_handler);
signal(SIGABRT, signal_handler);
#endif
actor_loop();
return 0;
}
int JS_ArrayLength(JSContext *js, JSValue a)
{
int64_t len;
JS_GetLength(js, a, &len);
return len;
}
int js2bool(JSContext *js, JSValue v) { return JS_ToBool(js,v); }
JSValue bool2js(JSContext *js, int b) { return JS_NewBool(js,b); }
JSValue number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); }
double js2number(JSContext *js, JSValue v) {
double g;
JS_ToFloat64(js, &g, v);
if (isnan(g)) g = 0;
return g;
}
uint64_t cell_random_fit() {
uint64_t buf;
randombytes((uint8_t *)&buf, sizeof(buf));
return buf >> 11;
}
double cell_random() {
uint64_t buf = cell_random_fit();
return (double)buf / 9007199254740992.0;
}
void cell_trace_sethook(cell_hook)
{
}
int uncaught_exception(JSContext *js, JSValue v)
{
cell_rt *rt = JS_GetContextOpaque(js);
if (!JS_HasException(js)) {
JS_FreeValue(js,v);
return 1;
}
JSValue exp = JS_GetException(js);
JSValue message = JS_GetPropertyStr(js, exp, "message");
const char *msg_str = JS_ToCString(js, message);
if (msg_str) {
printf("Exception: %s\n", msg_str);
JS_FreeCString(js, msg_str);
}
JS_FreeValue(js, message);
JSValue stack = JS_GetPropertyStr(js, exp, "stack");
const char *stack_str = JS_ToCString(js, stack);
if (stack_str) {
printf("Stack:\n%s\n", stack_str);
JS_FreeCString(js, stack_str);
}
JS_FreeValue(js, stack);
JS_FreeValue(js, exp);
JS_FreeValue(js, v);
return 0;
}