Merge branch 'cell_lsp'

This commit is contained in:
2026-02-17 00:28:17 -06:00
6 changed files with 50 additions and 103 deletions

View File

@@ -2,8 +2,8 @@
## Building ## Building
Recompile after changes: `make` Build (or rebuild after changes): `make`
Bootstrap from scratch (first time): `make bootstrap` Install to system: `make install`
Run `cell --help` to see all CLI flags. Run `cell --help` to see all CLI flags.
## Code Style ## Code Style

View File

@@ -1,83 +1,30 @@
# Development build: creates libcell_runtime.dylib + thin main wrapper BUILD = build
# This is the default target for working on cell itself INSTALL_BIN = /opt/homebrew/bin
# INSTALL_LIB = /opt/homebrew/lib
# If cell doesn't exist yet, use 'make bootstrap' first (requires meson) INSTALL_INC = /opt/homebrew/include
# or manually build with meson once. CELL_SHOP = $(HOME)/.cell
#
# The cell shop is at ~/.cell and core scripts are installed to ~/.cell/core
CELL_SHOP = $(HOME)/.cell all: $(BUILD)/build.ninja
CELL_CORE_PACKAGE = $(CELL_SHOP)/packages/core meson compile -C $(BUILD)
cp $(BUILD)/libcell_runtime.dylib .
cp $(BUILD)/cell .
doit: bootstrap $(BUILD)/build.ninja:
meson setup $(BUILD) -Dbuildtype=debugoptimized
maker: install install: all $(CELL_SHOP)
cp cell $(INSTALL_BIN)/cell
cp libcell_runtime.dylib $(INSTALL_LIB)/
cp source/cell.h source/quickjs.h source/wota.h $(INSTALL_INC)/
rm -rf $(CELL_SHOP)/packages/core
ln -s $(CURDIR) $(CELL_SHOP)/packages/core
@echo "Installed cell to $(INSTALL_BIN) and $(INSTALL_LIB)"
makecell:
cell pack core -o cell
cp cell /opt/homebrew/bin/
# Install core: symlink this directory to ~/.cell/core
install: cell $(CELL_SHOP)
@echo "Linking cell core to $(CELL_CORE_PACKAGE)"
rm -rf $(CELL_CORE_PACKAGE)
ln -s $(PWD) $(CELL_CORE_PACKAGE)
cp cell /opt/homebrew/bin/
cp libcell_runtime.dylib /opt/homebrew/lib/
@echo "Core installed."
cell: libcell_runtime.dylib cell_main
cp cell_main cell
chmod +x cell
cp cell /opt/homebrew/bin/cell
cp libcell_runtime.dylib /opt/homebrew/lib/
# Build the shared runtime library (everything except main.c)
# Uses existing cell to run build -d
libcell_runtime.dylib: $(CELL_SHOP)/build/dynamic
cell build -d
cp $(CELL_SHOP)/build/dynamic/libcell_runtime.dylib .
# Build the thin main wrapper that links to libcell_runtime
cell_main: source/main.c libcell_runtime.dylib
cc -o cell_main source/main.c -L. -lcell_runtime -Wl,-rpath,@loader_path -Wl,-rpath,/opt/homebrew/lib
# Create the cell shop directories
$(CELL_SHOP): $(CELL_SHOP):
mkdir -p $(CELL_SHOP) mkdir -p $(CELL_SHOP)/packages $(CELL_SHOP)/cache $(CELL_SHOP)/build
mkdir -p $(CELL_SHOP)/packages
mkdir -p $(CELL_SHOP)/cache
mkdir -p $(CELL_SHOP)/build
$(CELL_CORE):
ln -s $(PWD) $(CELL_CORE)
# Static build: creates a fully static cell binary (for distribution)
static:
cell build
cp $(CELL_SHOP)/build/static/cell .
# Bootstrap: build cell from scratch using meson (only needed once)
# Also installs core scripts to ~/.cell/core
bootstrap:
meson setup build_bootstrap -Dbuildtype=debugoptimized
meson compile -C build_bootstrap
cp build_bootstrap/cell .
cp build_bootstrap/libcell_runtime.dylib .
@echo "Bootstrap complete. Run cell like ./cell --dev to use a local shop at .cell."
# Clean build artifacts
clean: clean:
rm -rf $(CELL_SHOP)/build build_bootstrap rm -rf $(BUILD)
rm -f cell cell_main libcell_runtime.dylib rm -f cell libcell_runtime.dylib
# Ensure dynamic build directory exists .PHONY: all install clean
$(CELL_SHOP)/build/dynamic: $(CELL_SHOP)
mkdir -p $(CELL_SHOP)/build/dynamic
# Legacy meson target
meson:
meson setup build_dbg -Dbuildtype=debugoptimized
meson install -C build_dbg
.PHONY: cell static bootstrap clean meson install

View File

@@ -1,13 +1,6 @@
[dependencies]
cell-steam = "/Users/johnalanbrook/work/cell-steam"
cell-sdl3 = "/Users/johnalanbrook/work/cell-sdl3"
[compilation] [compilation]
CFLAGS = "-Isource -Wno-incompatible-pointer-types -Wno-missing-braces -Wno-strict-prototypes -Wno-unused-function -Wno-int-conversion"
LDFLAGS = "-lstdc++ -lm"
[compilation.macos_arm64]
CFLAGS = "-x objective-c"
LDFLAGS = "-framework CoreFoundation -framework CFNetwork"
[compilation.playdate] [compilation.playdate]
CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API" CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API"
[compilation.windows]
LDFLAGS = "-lws2_32 -lwinmm -liphlpapi -lbcrypt -lwinhttp -static-libgcc -static-libstdc++"

View File

@@ -56,6 +56,7 @@
"vscode-languageserver-protocol": "^3.17.0" "vscode-languageserver-protocol": "^3.17.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.19.33",
"@types/vscode": "^1.75.0", "@types/vscode": "^1.75.0",
"typescript": "^5.0.0" "typescript": "^5.0.0"
} }

View File

@@ -75,7 +75,7 @@ package.load_config = function(name)
package.save_config = function(name, config) package.save_config = function(name, config)
{ {
var config_path = get_path(name) + '/cell.toml' var config_path = get_path(name) + '/cell.toml'
fd.slurpwrite(config_path, utf8.encode(toml.encode(config))) fd.slurpwrite(config_path, stone(blob(toml.encode(config))))
} }
package.dependencies = function(name) package.dependencies = function(name)

View File

@@ -2113,7 +2113,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
/* Search frame chain for a disruption handler. /* Search frame chain for a disruption handler.
Use frame_pc to track each frame's execution point: Use frame_pc to track each frame's execution point:
- For the faulting frame, it's the current pc. - For the faulting frame, it's the current pc.
- For unwound caller frames, read from frame->address. */ - For unwound caller frames, read from frame->address.
Keep frame_ref.val at the faulting frame and preserve caller
links so the trace walk can show the full call chain. */
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); /* re-chase after GC */ frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); /* re-chase after GC */
{ {
uint32_t frame_pc = pc; uint32_t frame_pc = pc;
@@ -2125,28 +2127,34 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
env = fn->u.reg.env_record; env = fn->u.reg.env_record;
pc = code->disruption_pc; pc = code->disruption_pc;
ctx->disruption_reported = FALSE; ctx->disruption_reported = FALSE;
frame_ref.val = JS_MKPTR(frame); /* root handler frame for GC */
break; break;
} }
if (JS_IsNull(frame->caller)) { if (JS_IsNull(frame->caller)) {
if (!ctx->disruption_reported) { if (!ctx->disruption_reported) {
const char *fn_name = code->name_cstr ? code->name_cstr : "<anonymous>"; /* Use faulting frame (frame_ref.val) for the header */
const char *file = code->filename_cstr ? code->filename_cstr : "<unknown>"; JSFrameRegister *fault = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
JSFunction *fault_fn = JS_VALUE_GET_FUNCTION(fault->function);
JSCodeRegister *fault_code = fault_fn->u.reg.code;
const char *fn_name = fault_code->name_cstr ? fault_code->name_cstr : "<anonymous>";
const char *file = fault_code->filename_cstr ? fault_code->filename_cstr : "<unknown>";
uint16_t line = 0, col = 0; uint16_t line = 0, col = 0;
if (code->line_table && frame_pc > 0 && frame_pc - 1 < code->instr_count) { uint32_t fpc = pc > 0 ? pc - 1 : 0;
line = code->line_table[frame_pc - 1].line; if (fault_code->line_table && fpc < fault_code->instr_count) {
col = code->line_table[frame_pc - 1].col; line = fault_code->line_table[fpc].line;
col = fault_code->line_table[fpc].col;
} }
fprintf(stderr, "unhandled disruption in %s (%s:%u:%u)\n", fn_name, file, line, col); fprintf(stderr, "unhandled disruption in %s (%s:%u:%u)\n", fn_name, file, line, col);
/* Walk and print the frame chain as a stack trace */ /* Walk intact caller chain for stack trace */
{ {
JSFrameRegister *trace_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); JSFrameRegister *trace_frame = fault;
int first = 1; int first = 1;
while (trace_frame) { while (trace_frame) {
if (!mist_is_function(trace_frame->function)) break; if (!mist_is_function(trace_frame->function)) break;
JSFunction *trace_fn = JS_VALUE_GET_FUNCTION(trace_frame->function); JSFunction *trace_fn = JS_VALUE_GET_FUNCTION(trace_frame->function);
if (trace_fn->kind == JS_FUNC_KIND_REGISTER && trace_fn->u.reg.code) { if (trace_fn->kind == JS_FUNC_KIND_REGISTER && trace_fn->u.reg.code) {
JSCodeRegister *tc = trace_fn->u.reg.code; JSCodeRegister *tc = trace_fn->u.reg.code;
uint32_t tpc = first ? (frame_pc > 0 ? frame_pc - 1 : 0) uint32_t tpc = first ? fpc
: (uint32_t)(JS_VALUE_GET_INT(trace_frame->address) >> 16); : (uint32_t)(JS_VALUE_GET_INT(trace_frame->address) >> 16);
uint16_t tl = 0, tcol = 0; uint16_t tl = 0, tcol = 0;
if (tc->line_table && tpc < tc->instr_count) { if (tc->line_table && tpc < tc->instr_count) {
@@ -2164,15 +2172,13 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
} }
ctx->disruption_reported = TRUE; ctx->disruption_reported = TRUE;
} }
frame_ref.val = JS_MKPTR(frame); /* update root for GC / done */
result = JS_Throw(ctx, JS_NULL); result = JS_Throw(ctx, JS_NULL);
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto done; goto done;
} }
/* Unwind one frame — read caller's saved pc from its address field */ /* Advance to caller — keep chain intact (no nulling caller links) */
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16); frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
} }
} }