refactor(lang): rename the ptr/ptrs types to pointer/pointers
Expand the abbreviated pointer types to full words on the language surface: ptr -> pointer (a raw address / FFI handle) ptrs -> pointers (a buffer of pointers) The Ludic type name is distinct from LLVM's own `ptr` spelling: llty() maps `pointer`/`pointers` to LLVM `ptr`, and the emitted IR keeps `ptr`, so only the Ludic-level surface changes. Rewrites type annotations across all sources, the 8 hardcoded pointer type-tags, the `pointers`-buffer indexing in emit_addr, the grammars/LSP/JetBrains tokens, and the docs (type-ptr -> type-pointer, type-ptrs -> type-pointers). int/bool keep their conventional short spelling (like Math). Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b7745a4600
commit
effb3f637f
76 changed files with 516 additions and 516 deletions
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
# compile a Ludic source to a native binary in bin/ via ludicc + clang (-O2).
|
||||
# Returns true on success. Used for x itself and the editor tools.
|
||||
function build_tool(name: ptr, src: ptr) -> bool {
|
||||
function build_tool(name: pointer, src: pointer) -> bool {
|
||||
let ll = `build/{name}.ll`
|
||||
if not shq(`bin/ludicc {src} --emit-llvm -o {ll} 2>/dev/null`) { print(`build failed: {name} (compile)`); return false }
|
||||
# write to a temp then move, so a running bin/x can rebuild itself in place
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ program X {
|
|||
}
|
||||
|
||||
# a positional argument, or a default when absent
|
||||
function argn(i: int, dflt: ptr) -> ptr {
|
||||
function argn(i: int, dflt: pointer) -> pointer {
|
||||
if (i < arg_count()) { return arg(i) }
|
||||
return dflt
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
# ---- file IO ----------------------------------------------------------------
|
||||
|
||||
# read a whole file into a fresh NUL-terminated buffer (null if it cannot open)
|
||||
function read_file(path: ptr) -> ptr {
|
||||
function read_file(path: pointer) -> pointer {
|
||||
let f = file_open(path, "rb")
|
||||
if (f == null) { return null }
|
||||
file_seek(f, 0, 2)
|
||||
|
|
@ -27,7 +27,7 @@ function read_file(path: ptr) -> ptr {
|
|||
}
|
||||
|
||||
# overwrite `path` with `s`; returns false if it could not be opened
|
||||
function write_file(path: ptr, s: ptr) -> bool {
|
||||
function write_file(path: pointer, s: pointer) -> bool {
|
||||
let f = file_open(path, "wb")
|
||||
if (f == null) { return false }
|
||||
file_write(f, s, len(s))
|
||||
|
|
@ -35,22 +35,22 @@ function write_file(path: ptr, s: ptr) -> bool {
|
|||
return true
|
||||
}
|
||||
|
||||
function file_exists(path: ptr) -> bool { return shq(`test -e {path}`) }
|
||||
function is_exec(path: ptr) -> bool { return shq(`test -x {path}`) }
|
||||
function file_exists(path: pointer) -> bool { return shq(`test -e {path}`) }
|
||||
function is_exec(path: pointer) -> bool { return shq(`test -x {path}`) }
|
||||
# is `a` newer than `b` (like the shell's `-nt`)?
|
||||
function newer(a: ptr, b: ptr) -> bool { return shq(`test {a} -nt {b}`) }
|
||||
function newer(a: pointer, b: pointer) -> bool { return shq(`test {a} -nt {b}`) }
|
||||
|
||||
# ---- process control --------------------------------------------------------
|
||||
|
||||
# `run` returns the raw wait status; the program's exit code is the high byte.
|
||||
function exit_code(st: int) -> int { return (st >> 8) & 255 }
|
||||
# run a command, returning its exit code (0 = success)
|
||||
function sh(cmd: ptr) -> int { return exit_code(run(cmd)) }
|
||||
function sh(cmd: pointer) -> int { return exit_code(run(cmd)) }
|
||||
# run a command, true when it succeeded
|
||||
function shq(cmd: ptr) -> bool { return exit_code(run(cmd)) == 0 }
|
||||
function shq(cmd: pointer) -> bool { return exit_code(run(cmd)) == 0 }
|
||||
|
||||
# run `cmd` and return its stdout (stderr discarded). Never null.
|
||||
function capture(cmd: ptr) -> ptr {
|
||||
function capture(cmd: pointer) -> pointer {
|
||||
let tmp = "/tmp/x_capture.out"
|
||||
run(`{cmd} > {tmp} 2>/dev/null`)
|
||||
let s = read_file(tmp)
|
||||
|
|
@ -60,16 +60,16 @@ function capture(cmd: ptr) -> ptr {
|
|||
|
||||
# run `cmd`, join its output lines with single spaces and trim — the Ludic twin
|
||||
# of the shell idiom `$(cmd | tr '\n' ' ' | sed 's/ *$//')`.
|
||||
function capture_line(cmd: ptr) -> ptr {
|
||||
function capture_line(cmd: pointer) -> pointer {
|
||||
return capture(`{cmd} | tr '\n' ' ' | sed 's/ *$//'`)
|
||||
}
|
||||
|
||||
# the last line of a command's output (for one-line error messages)
|
||||
function capture_tail(cmd: ptr) -> ptr {
|
||||
function capture_tail(cmd: pointer) -> pointer {
|
||||
return capture(`{cmd} 2>&1 | tail -1`)
|
||||
}
|
||||
|
||||
function getenv_or(name: ptr, dflt: ptr) -> ptr {
|
||||
function getenv_or(name: pointer, dflt: pointer) -> pointer {
|
||||
let v = getenv(name)
|
||||
if (v == null) { return dflt }
|
||||
return v
|
||||
|
|
@ -78,34 +78,34 @@ function getenv_or(name: ptr, dflt: ptr) -> ptr {
|
|||
# ---- stdout helpers ---------------------------------------------------------
|
||||
|
||||
# write `s` with no trailing newline (print() always adds one)
|
||||
function out(s: ptr) -> void { file_write(file_stdout(), s, len(s)) }
|
||||
function err(s: ptr) -> void { file_write(file_stderr(), s, len(s)) }
|
||||
function out(s: pointer) -> void { file_write(file_stdout(), s, len(s)) }
|
||||
function err(s: pointer) -> void { file_write(file_stderr(), s, len(s)) }
|
||||
|
||||
# an ESC byte — the lexer has no \033, so build it by hand
|
||||
function esc() -> ptr { let b = bytes(2); b[0] = 27; b[1] = 0; return b }
|
||||
function c_green() -> ptr { return esc() + "[32m" }
|
||||
function c_red() -> ptr { return esc() + "[31m" }
|
||||
function c_reset() -> ptr { return esc() + "[0m" }
|
||||
function esc() -> pointer { let b = bytes(2); b[0] = 27; b[1] = 0; return b }
|
||||
function c_green() -> pointer { return esc() + "[32m" }
|
||||
function c_red() -> pointer { return esc() + "[31m" }
|
||||
function c_reset() -> pointer { return esc() + "[0m" }
|
||||
|
||||
# ---- the PASS/FAIL test harness ---------------------------------------------
|
||||
|
||||
var PASS: int = 0
|
||||
var FAIL: int = 0
|
||||
|
||||
function ok(msg: ptr) -> void {
|
||||
function ok(msg: pointer) -> void {
|
||||
PASS = PASS + 1
|
||||
print(` {c_green()}PASS{c_reset()} {msg}`)
|
||||
}
|
||||
function bad(msg: ptr) -> void {
|
||||
function bad(msg: pointer) -> void {
|
||||
FAIL = FAIL + 1
|
||||
print(` {c_red()}FAIL{c_reset()} {msg}`)
|
||||
}
|
||||
function bad2(msg: ptr, detail: ptr) -> void {
|
||||
function bad2(msg: pointer, detail: pointer) -> void {
|
||||
bad(msg)
|
||||
print(` {detail}`)
|
||||
}
|
||||
# assert two strings equal, reporting the mismatch
|
||||
function check(label: ptr, got: ptr, want: ptr) -> void {
|
||||
function check(label: pointer, got: pointer, want: pointer) -> void {
|
||||
if (got == want) { ok(label) }
|
||||
else { bad2(label, `expected [{want}] got [{got}]`) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
# now lives here once, in selfhost_frags().
|
||||
|
||||
# the C toolchain driver (clang) that assembles and links the emitted IR
|
||||
function cc() -> ptr { return getenv_or("LUDIC_CC", "clang") }
|
||||
function cc() -> pointer { return getenv_or("LUDIC_CC", "clang") }
|
||||
|
||||
# the self-host compiler's source fragments, in link order. This is THE list;
|
||||
# the old scripts each carried their own copy.
|
||||
function selfhost_frags() -> []ptr {
|
||||
let f = new []ptr
|
||||
function selfhost_frags() -> []pointer {
|
||||
let f = new []pointer
|
||||
push(f, "selfhost/str.ludic")
|
||||
push(f, "selfhost/buf.ludic")
|
||||
push(f, "selfhost/io.ludic")
|
||||
|
|
@ -52,7 +52,7 @@ function selfhost_frags() -> []ptr {
|
|||
|
||||
# concatenate the fragments into `program SelfHost { ... }` at `outpath`.
|
||||
# This is the pure-Ludic equivalent of the scripts' `{ echo; for; cat; }` block.
|
||||
function write_selfhost_src(outpath: ptr) -> bool {
|
||||
function write_selfhost_src(outpath: pointer) -> bool {
|
||||
let f = file_open(outpath, "wb")
|
||||
if (f == null) { return false }
|
||||
let hdr = "program SelfHost {\n"
|
||||
|
|
@ -72,7 +72,7 @@ function write_selfhost_src(outpath: ptr) -> bool {
|
|||
}
|
||||
|
||||
# count the lines in a file (for the progress notes the scripts printed)
|
||||
function line_count(path: ptr) -> ptr {
|
||||
function line_count(path: pointer) -> pointer {
|
||||
return capture_line(`wc -l < {path}`)
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ function ensure_ludicc() -> void {
|
|||
|
||||
# ---- selfhost-build: assemble + compile the self-host compiler ---------------
|
||||
# usage: x selfhost-build [ludicc] [outbin] (defaults: bin/ludicc, build/selfhost)
|
||||
function cmd_selfhost_build(lc: ptr, outbin: ptr) -> int {
|
||||
function cmd_selfhost_build(lc: pointer, outbin: pointer) -> int {
|
||||
run("mkdir -p build")
|
||||
let src = "build/selfhost.ludic"
|
||||
if not write_selfhost_src(src) { err("x: cannot write build/selfhost.ludic\n"); return 1 }
|
||||
|
|
@ -104,7 +104,7 @@ function cmd_selfhost_build(lc: ptr, outbin: ptr) -> int {
|
|||
|
||||
# ---- sh-compile: compile one .ludic with a given selfhost binary and link ----
|
||||
# usage: x sh-compile <selfhost-binary> <input.ludic> <output-binary>
|
||||
function cmd_sh_compile(shbin: ptr, in: ptr, outbin: ptr) -> int {
|
||||
function cmd_sh_compile(shbin: pointer, in: pointer, outbin: pointer) -> int {
|
||||
if not shq(`{shbin} {in} > {outbin}.ll`) { return 1 }
|
||||
if not shq(`{cc()} {outbin}.ll -o {outbin}`) { return 1 }
|
||||
return 0
|
||||
|
|
@ -116,7 +116,7 @@ function cmd_sh_compile(shbin: ptr, in: ptr, outbin: ptr) -> int {
|
|||
|
||||
# the quiet core, reused by the test suites; returns true on success. On failure
|
||||
# the self-host/link diagnostics are left in /tmp/x_gb.err.
|
||||
function game_build_ok(shbin: ptr, game: ptr, outbin: ptr) -> bool {
|
||||
function game_build_ok(shbin: pointer, game: pointer, outbin: pointer) -> bool {
|
||||
let ll = `{outbin}.ll`
|
||||
if not shq(`{shbin} {game} > {ll} 2>/tmp/x_gb.err`) { return false }
|
||||
if not shq(`{cc()} -O2 {ll} -o {outbin} 2>/tmp/x_gb.err`) { return false }
|
||||
|
|
@ -125,7 +125,7 @@ function game_build_ok(shbin: ptr, game: ptr, outbin: ptr) -> bool {
|
|||
}
|
||||
|
||||
# usage: x game-build <selfhost-binary> <game.ludic> <out-binary>
|
||||
function cmd_game_build(shbin: ptr, game: ptr, outbin: ptr) -> int {
|
||||
function cmd_game_build(shbin: pointer, game: pointer, outbin: pointer) -> int {
|
||||
if game_build_ok(shbin, game, outbin) { print(`built {outbin}`); return 0 }
|
||||
print("build failed:")
|
||||
out(capture("grep -i error /tmp/x_gb.err | head -5"))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# fixpoint). Replaces selfhost/test.sh.
|
||||
|
||||
# compile selfhost/tests/<name>.ludic with bin/ludicc, assemble, run, compare
|
||||
function sh_case(name: ptr, exp: ptr) -> void {
|
||||
function sh_case(name: pointer, exp: pointer) -> void {
|
||||
let ll = `/tmp/x_sh_{name}.ll`
|
||||
let er = `/tmp/x_sh_{name}.err`
|
||||
let bn = `/tmp/x_sh_{name}`
|
||||
|
|
@ -16,7 +16,7 @@ function sh_case(name: ptr, exp: ptr) -> void {
|
|||
}
|
||||
|
||||
# compile examples/<name>.ludic as a game and diff its render against the golden
|
||||
function game_case(name: ptr, keys: ptr) -> void {
|
||||
function game_case(name: pointer, keys: pointer) -> void {
|
||||
if not game_build_ok("bin/ludicc", `examples/{name}.ludic`, `/tmp/x_g_{name}`) { bad(`{name}: build`); return }
|
||||
run(`printf '%s' '{keys}' | /tmp/x_g_{name} >/dev/null 2>&1`)
|
||||
if shq(`cmp -s selfhost/golden/{name}.ppm out.ppm`) { ok(`{name} matches the golden render`) }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# compile a feature example as a game, run it (optional keys on stdin) and match
|
||||
# its stdout against the expected space-joined output.
|
||||
function feat_case(name: ptr, keys: ptr, exp: ptr, label: ptr) -> void {
|
||||
function feat_case(name: pointer, keys: pointer, exp: pointer, label: pointer) -> void {
|
||||
if not game_build_ok("bin/ludicc", `examples/{name}.ludic`, `/tmp/x_e_{name}`) {
|
||||
bad2(label, capture_line("grep -i error /tmp/x_gb.err | head -1")); return
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ function feat_case(name: ptr, keys: ptr, exp: ptr, label: ptr) -> void {
|
|||
}
|
||||
|
||||
# a "does it still compile" smoke test (parse -> lower -> link), no run
|
||||
function qsmoke(name: ptr) -> void {
|
||||
function qsmoke(name: pointer) -> void {
|
||||
if game_build_ok("bin/ludicc", `examples/{name}.ludic`, `/tmp/x_q_{name}`) {
|
||||
ok(`{name} compiles (@Queries desugars to S_QUERY)`)
|
||||
} else { bad2(name, capture_line("grep -i error /tmp/x_gb.err | head -1")) }
|
||||
|
|
@ -28,7 +28,7 @@ function qsmoke(name: ptr) -> void {
|
|||
|
||||
# a pure-Ludic example that drives and asserts itself: compile headless to IR,
|
||||
# let clang assemble it, run, and compare stdout. No C host and no C compiled.
|
||||
function net_case(name: ptr, exp: ptr) -> void {
|
||||
function net_case(name: pointer, exp: pointer) -> void {
|
||||
let ll = `/tmp/x_n_{name}.ll`
|
||||
let log = `/tmp/x_n_{name}.out`
|
||||
if not shq(`bin/ludicc --headless examples/{name}.ludic --emit-llvm -o {ll} > {log} 2>&1`) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# driven through python3/node (they are not project shell scripts), invoked here.
|
||||
|
||||
# refresh one editor-copy of a shared grammar file if it has drifted
|
||||
function sync_one(shared: ptr, dst: ptr) -> void {
|
||||
function sync_one(shared: pointer, dst: pointer) -> void {
|
||||
if not shq(`cmp -s {shared} {dst}`) {
|
||||
run(`cp {shared} {dst}`)
|
||||
print(`sync: {shared} -> {dst}`)
|
||||
|
|
@ -25,7 +25,7 @@ function sync_vscode_grammar() -> void {
|
|||
}
|
||||
|
||||
# is `flag` present anywhere in argv?
|
||||
function has_flag(flag: ptr) -> bool {
|
||||
function has_flag(flag: pointer) -> bool {
|
||||
var i = 2
|
||||
while i < arg_count() { if (arg(i) == flag) { return true }; i = i + 1 }
|
||||
return false
|
||||
|
|
@ -172,13 +172,13 @@ function cmd_test_tools() -> int {
|
|||
return report()
|
||||
}
|
||||
|
||||
function test_json(path: ptr) -> void {
|
||||
function test_json(path: pointer) -> void {
|
||||
let bn = capture_line(`basename {path}`)
|
||||
if shq(`python3 -c 'import json,sys;json.load(open(sys.argv[1]))' {path} 2>/dev/null`) {
|
||||
ok(`valid JSON: {bn}`)
|
||||
} else { bad(`invalid JSON: {path}`) }
|
||||
}
|
||||
function test_xml(path: ptr) -> void {
|
||||
function test_xml(path: pointer) -> void {
|
||||
let bn = capture_line(`basename {path}`)
|
||||
if shq(`python3 -c 'import xml.dom.minidom,sys;xml.dom.minidom.parse(sys.argv[1])' {path} 2>/dev/null`) {
|
||||
ok(`valid XML: {bn}`)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue