Merge branch 'cell_lsp'
This commit is contained in:
@@ -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
|
||||||
|
|||||||
97
Makefile
97
Makefile
@@ -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
|
|
||||||
|
|||||||
15
cell.toml
15
cell.toml
@@ -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++"
|
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user