From effb3f637f1e7296612754eaf4a33762c54a8d01 Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Sun, 30 Aug 2026 01:58:54 +0300 Subject: [PATCH] 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 --- BOOTSTRAP.md | 22 +- COMPILING.md | 6 +- LUANTI-ROADMAP.md | 2 +- MOBILE-DESIGN.md | 8 +- NETWORKING-DESIGN.md | 6 +- docs/language/annotations/annot-sync.md | 2 +- docs/language/builtins/fn-bytes.md | 2 +- docs/language/builtins/fn-file_stderr.md | 2 +- docs/language/builtins/fn-file_stdout.md | 2 +- docs/language/memory/memory-bytes.md | 2 +- docs/language/operators/op-literals.md | 2 +- docs/language/structure/kw-extern.md | 2 +- docs/language/system/system-file_open.md | 2 +- docs/language/system/system-stderr.md | 2 +- docs/language/system/system-stdout.md | 2 +- docs/language/types/type-byte.md | 2 +- docs/language/types/type-pointer.md | 18 ++ docs/language/types/type-pointers.md | 25 ++ docs/language/types/type-ptr.md | 18 -- docs/language/types/type-ptrs.md | 25 -- docs/language/types/type-words.md | 2 +- examples/world_mixed.ludic | 2 +- runtime/native/core.ludic | 14 +- runtime/native/image.ludic | 8 +- runtime/native/inflate.ludic | 18 +- runtime/native/truetype.ludic | 16 +- runtime/native/truetype_raster.ludic | 4 +- runtime/native/ui.ludic | 10 +- selfhost/ast.ludic | 4 +- selfhost/buf.ludic | 6 +- selfhost/emit_addr.ludic | 8 +- selfhost/emit_collide.ludic | 8 +- selfhost/emit_color.ludic | 2 +- selfhost/emit_colorfn.ludic | 10 +- selfhost/emit_core.ludic | 110 ++++----- selfhost/emit_decl.ludic | 8 +- selfhost/emit_ease.ludic | 6 +- selfhost/emit_expr.ludic | 44 ++-- selfhost/emit_game.ludic | 4 +- selfhost/emit_hash.ludic | 10 +- selfhost/emit_head.ludic | 4 +- selfhost/emit_intrin.ludic | 16 +- selfhost/emit_intrin2.ludic | 6 +- selfhost/emit_list.ludic | 8 +- selfhost/emit_math.ludic | 16 +- selfhost/emit_mem.ludic | 6 +- selfhost/emit_net.ludic | 12 +- selfhost/emit_new.ludic | 8 +- selfhost/emit_query.ludic | 2 +- selfhost/emit_save.ludic | 8 +- selfhost/emit_spawn.ludic | 6 +- selfhost/emit_stmt.ludic | 8 +- selfhost/emit_text.ludic | 4 +- selfhost/emit_time.ludic | 4 +- selfhost/emit_ui.ludic | 10 +- selfhost/io.ludic | 4 +- selfhost/lex.ludic | 8 +- selfhost/ludicc.seed.ll | 20 +- selfhost/main.ludic | 10 +- selfhost/parse.ludic | 62 ++--- selfhost/str.ludic | 2 +- tools/atlas.ludic | 4 +- tools/docgen/inventory.json | 4 +- .../main/kotlin/io/ludic/ide/LudicTokens.kt | 2 +- tools/editors/shared/ludic.tmLanguage.json | 2 +- .../vscode/syntaxes/ludic.tmLanguage.json | 2 +- tools/ludic-tools/fmt.ludic | 46 ++-- tools/ludic-tools/lsp.ludic | 218 +++++++++--------- tools/ludic-tools/ludic_syntax.h | 2 +- tools/x/build.ludic | 2 +- tools/x/main.ludic | 2 +- tools/x/prelude.ludic | 42 ++-- tools/x/selfhost.ludic | 18 +- tools/x/selfhost_test.ludic | 4 +- tools/x/test.ludic | 6 +- tools/x/tools.ludic | 8 +- 76 files changed, 516 insertions(+), 516 deletions(-) create mode 100644 docs/language/types/type-pointer.md create mode 100644 docs/language/types/type-pointers.md delete mode 100644 docs/language/types/type-ptr.md delete mode 100644 docs/language/types/type-ptrs.md diff --git a/BOOTSTRAP.md b/BOOTSTRAP.md index 05ad7a75..b2cfbbde 100644 --- a/BOOTSTRAP.md +++ b/BOOTSTRAP.md @@ -109,15 +109,15 @@ All verified. A compiler needs each of these, and each one works today. | Deep recursion (recursive-descent parsing) | ✅ | 5,000 frames, no crash | | Heap allocation | ✅ | `mem_alloc`, `mem_free`, `mem_copy`, `mem_set`; 1 MiB alloc verified | | Byte-level memory | ✅ | `peek8`/`poke8`, `peek32`/`poke32`, `peekp`/`pokep`, `ptr_add` | -| `ptr` locals, params, returns | ✅ | `function make(n: int) -> ptr` | -| `ptr` in a property field | ✅ | `property Nd { kind: int = 0, a: ptr = ptr_null() }` | +| `ptr` locals, params, returns | ✅ | `function make(n: int) -> pointer` | +| `ptr` in a property field | ✅ | `property Nd { kind: int = 0, a: pointer = ptr_null() }` | | String literals as readable bytes | ✅ | `peek8("hello", 1)` → `101` | -| `str` accepted where `ptr` expected | ✅ | `f("A")` into `function f(p: ptr)` | +| `str` accepted where `ptr` expected | ✅ | `f("A")` into `function f(p: pointer)` | | String comparison, **hand-written in Ludic** | ✅ | `streq` over `peek8` | | Integer → decimal, **hand-written in Ludic** | ✅ | `itoa(48291)` → `"48291"` | | File read: open/seek/tell/read/close | ✅ | full round-trip of a written file | | File write | ✅ | `file_open`/`file_write`/`file_close` | -| Module-level mutable state | ✅ | `var count: int`, `var heap: ptr` | +| Module-level mutable state | ✅ | `var count: int`, `var heap: pointer` | | `let` is mutable | ✅ | `i = i + 1` in a loop | | `while`, numeric `for i in a .. b` with runtime bounds | ✅ | | | `if` / `else if` / `else` chains | ✅ | | @@ -186,7 +186,7 @@ records. Today there are two workarounds, and both are bad at compiler scale: what `truetype.ludic` does, and it works, but every field access becomes a magic number. Across a 6,000-line compiler this is the difference between maintainable and not. -- **ECS entities as nodes** — verified working (`property Nd { kind, a: ptr }`), +- **ECS entities as nodes** — verified working (`property Nd { kind, a: pointer }`), and initially seductive because queries give you free traversal. **Do not do this.** `LUDIC_MAX_ENT` is 1024 in `native.c:18`; the entity world is a fixed array of per-property storage. A compiler needs hundreds of thousands of @@ -198,7 +198,7 @@ unblocks everything: ```ludic # doc-check: skip — proposed syntax: struct does not exist yet -struct Tok { kind: int = 0, text: ptr = ptr_null(), line: int = 0 } +struct Tok { kind: int = 0, text: pointer = ptr_null(), line: int = 0 } let t = new Tok # heap-allocated, fields seeded from defaults t.kind = T_ID @@ -278,7 +278,7 @@ Every table in a compiler grows: tokens, nodes, the output buffer. Hand-rolling alloc-copy-free works but is written once per table and gotten wrong once per table. -**Design.** `mem_realloc(p: ptr, n: int) -> ptr`. +**Design.** `mem_realloc(p: pointer, n: int) -> pointer`. **Lowering.** `declare ptr @realloc(ptr, )` plus one `INTRINSICS[]` entry. **Use `ll_size_t()` / `ll_widen()` for the size argument — do not @@ -303,7 +303,7 @@ plumbing is reused rather than duplicated: ```ludic # doc-check: skip — proposed signature notation, not code -file_stderr() -> ptr # then file_write(f, buf, n) as usual +file_stderr() -> pointer # then file_write(f, buf, n) as usual ``` **Lowering — note the portability wrinkle.** There is no portable `@stderr` @@ -870,7 +870,7 @@ program P { **String comparison, hand-written** ✅ → `1` ```ludic -function streq(a: ptr, b: ptr) -> bool { +function streq(a: pointer, b: pointer) -> bool { let i = 0 while true { let ca = peek8(a,i) @@ -885,7 +885,7 @@ function streq(a: ptr, b: ptr) -> bool { **Integer → string, hand-written** ✅ → `48291` ```ludic -function itoa(v: int, buf: ptr) -> int { +function itoa(v: int, buf: pointer) -> int { let n = 0 let x = v if x == 0 { poke8(buf,0,48); return 1 } @@ -972,7 +972,7 @@ parenthesisation) while `ludic-fmt` returns the input **unchanged**. ```ludic # doc-check: expect-error — every line here is a compile error by design while i < 10 { i = i + 1; if i == 3 { break } } # unknown identifier 'break' -struct Node { k: int, a: ptr } # expected declaration (got 'struct') +struct Node { k: int, a: pointer } # expected declaration (got 'struct') var t: [int; 8] # expected identifier (got '[') var h: fn = a # unknown type 'fn' for var h let p = &cb # fails to compile diff --git a/COMPILING.md b/COMPILING.md index f66849e3..fdec64f4 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -160,10 +160,10 @@ compiler intrinsics that lower to direct calls into the platform ABI. | intrinsic | lowers to | | --- | --- | -| `mem_alloc(n) -> ptr`, `mem_free`, `mem_copy`, `mem_set` | `malloc`, `free`, `memcpy`, `memset` | +| `mem_alloc(n) -> pointer`, `mem_free`, `mem_copy`, `mem_set` | `malloc`, `free`, `memcpy`, `memset` | | `peek8/peek32(p, i) -> int`, `poke8/poke32(p, i, v)` | `load` / `store` | -| `ptr_add(p, n) -> ptr`, `ptr_null()`, `ptr_is_null(p)` | `getelementptr`, `null` | -| `file_open(path, mode) -> ptr`, `file_read`, `file_write`, `file_close` | `fopen`, `fread`, `fwrite`, `fclose` | +| `ptr_add(p, n) -> pointer`, `ptr_null()`, `ptr_is_null(p)` | `getelementptr`, `null` | +| `file_open(path, mode) -> pointer`, `file_read`, `file_write`, `file_close` | `fopen`, `fread`, `fwrite`, `fclose` | | `read_byte() -> int`, `write_byte(c)`, `print_str(s)`, `print_int(n)` | `getchar`, `putchar`, `printf` | | `str_len(s) -> int`, `os_exit(code)`, `os_time() -> int` | `strlen`, `exit`, `time` | diff --git a/LUANTI-ROADMAP.md b/LUANTI-ROADMAP.md index fb0a913d..4e3c4b65 100644 --- a/LUANTI-ROADMAP.md +++ b/LUANTI-ROADMAP.md @@ -1211,7 +1211,7 @@ hand-rolled pointer arithmetic these features exist to delete. ```ludic # before (runtime/native/image.ludic today) -function px(img: ptr, x: int, y: int, w: int) -> int { return peek32(img, (y*w+x)*4) } +function px(img: pointer, x: int, y: int, w: int) -> int { return peek32(img, (y*w+x)*4) } # after struct Rgba { r: u8, g: u8, b: u8, a: u8 } diff --git a/MOBILE-DESIGN.md b/MOBILE-DESIGN.md index d651ff36..8589d975 100644 --- a/MOBILE-DESIGN.md +++ b/MOBILE-DESIGN.md @@ -185,7 +185,7 @@ explicitly built for. - **Touch input changes the input seam.** `win_poll()` returns a single `int` keycode today ([emit_intrin2.ludic:41](selfhost/emit_intrin2.ludic:41), [core.ludic:217](runtime/native/core.ludic:217)) — insufficient for touch, which - needs `(x, y, phase, id)`. Options: (a) a parallel `win_poll_touch() -> ptr` + needs `(x, y, phase, id)`. Options: (a) a parallel `win_poll_touch() -> pointer` draining an event queue, or (b) widen the input model to a small event struct for all platforms. This is the one place mobile forces a decision above the window seam. Proposed: add touch as a **separate** seam so keyboard platforms stay @@ -211,9 +211,9 @@ no new language feature, no new intrinsic: ```ludic # doc-check: skip — runtime/native/gfx3d.ludic, illustrative -extern function gl_gen_textures(n: int, out: ptr) -> void = "glGenTextures" -extern function gl_tex_image_2d(t: int, w: int, h: int, px: ptr) -> void = "gl_tex_image_2d" -extern function gl_draw_elements(mode: int, count: int, ty: int, idx: ptr) -> void = "glDrawElements" +extern function gl_gen_textures(n: int, out: pointer) -> void = "glGenTextures" +extern function gl_tex_image_2d(t: int, w: int, h: int, px: pointer) -> void = "gl_tex_image_2d" +extern function gl_draw_elements(mode: int, count: int, ty: int, idx: pointer) -> void = "glDrawElements" ``` Two phases, additive: diff --git a/NETWORKING-DESIGN.md b/NETWORKING-DESIGN.md index a18e2e0f..6a5d0324 100644 --- a/NETWORKING-DESIGN.md +++ b/NETWORKING-DESIGN.md @@ -151,9 +151,9 @@ directly from these; the high-level layer (§6) is sugar over them. | Primitive | Signature (sketch) | Enables | |---|---|---| -| **Transport seam** | `extern function net_send(peer: int, buf: ptr, len: int)` · `extern function net_poll(buf: ptr, cap: int) -> int` | any model; host binds UDP (native) or WebRTC/WebSocket (wasm), or a loopback for tests | -| **World snapshot ↔ buffer** | `world_save(buf: ptr) -> int` · `world_load(buf: ptr, len: int)` | rollback, replication, join/resync — generalizes `save()`/`load()` off the filesystem | -| **Generated serializers** | `serialize_(e: entity, buf: ptr) -> int` · `apply_(e: entity, buf: ptr, len: int)` | per-model, touch only the `@Sync` fields; emitted from the schema | +| **Transport seam** | `extern function net_send(peer: int, buf: pointer, len: int)` · `extern function net_poll(buf: pointer, cap: int) -> int` | any model; host binds UDP (native) or WebRTC/WebSocket (wasm), or a loopback for tests | +| **World snapshot ↔ buffer** | `world_save(buf: pointer) -> int` · `world_load(buf: pointer, len: int)` | rollback, replication, join/resync — generalizes `save()`/`load()` off the filesystem | +| **Generated serializers** | `serialize_(e: entity, buf: pointer) -> int` · `apply_(e: entity, buf: pointer, len: int)` | per-model, touch only the `@Sync` fields; emitted from the schema | | **Ownership** | `owner(e: entity) -> int` · `set_owner(e: entity, id: int)` | authority checks, per-entity owner metadata (an `@L_owner` array, like `@L_kind`) | | **Role registers** | `is_server() -> bool` · `is_owner(e: entity) -> bool` · `local_id() -> int` | the runtime sets these; role-guarded dispatch reads them | | **Drivable sim** | `tick_fixed()` · `tick_render()` · seed get/set | a developer-owned loop for prediction/rollback (also: replay, headless tests, AI) | diff --git a/docs/language/annotations/annot-sync.md b/docs/language/annotations/annot-sync.md index ff16d21c..e078a299 100644 --- a/docs/language/annotations/annot-sync.md +++ b/docs/language/annotations/annot-sync.md @@ -9,7 +9,7 @@ tip: Mark fields as replicated and models as owned so the compiler generates net order: 4 --- -These are the two declarative switches at the top of Ludic's networking: @Sync says what replicates and @Owned says who owns an instance. Replication is opt-in at the field level and decided per model use-site — a field crosses the wire only when it is both replicable (marked @Sync, either on the field or via @Sync property P which marks every field of P) and participating (the model marks the component @Sync). So the same property can replicate in one model and not another, and there is no @NoSync because the surface is purely additive. From these marks the compiler generates the per-model serialize/apply codecs; @Sync on a non-POD-scalar field (like a ptr) is a compile error, since a machine-local pointer cannot cross the wire. @Owned adds the owner slot the ownership builtins and @Predicted read. See the dedicated @Owned page for ownership details. +These are the two declarative switches at the top of Ludic's networking: @Sync says what replicates and @Owned says who owns an instance. Replication is opt-in at the field level and decided per model use-site — a field crosses the wire only when it is both replicable (marked @Sync, either on the field or via @Sync property P which marks every field of P) and participating (the model marks the component @Sync). So the same property can replicate in one model and not another, and there is no @NoSync because the surface is purely additive. From these marks the compiler generates the per-model serialize/apply codecs; @Sync on a non-POD-scalar field (like a pointer) is a compile error, since a machine-local pointer cannot cross the wire. @Owned adds the owner slot the ownership builtins and @Predicted read. See the dedicated @Owned page for ownership details. ```ludic program SyncedWorld { diff --git a/docs/language/builtins/fn-bytes.md b/docs/language/builtins/fn-bytes.md index 43525e25..1cb75a0d 100644 --- a/docs/language/builtins/fn-bytes.md +++ b/docs/language/builtins/fn-bytes.md @@ -4,7 +4,7 @@ name: bytes category: builtins kind: builtin tokens: bytes -sig: bytes(n) -> ptr +sig: bytes(n) -> pointer tip: Allocate a raw buffer of n bytes and return a pointer to it. order: 50 --- diff --git a/docs/language/builtins/fn-file_stderr.md b/docs/language/builtins/fn-file_stderr.md index 9ed4f1c6..d57addf1 100644 --- a/docs/language/builtins/fn-file_stderr.md +++ b/docs/language/builtins/fn-file_stderr.md @@ -4,7 +4,7 @@ name: file_stderr category: builtins kind: builtin tokens: file_stderr -sig: file_stderr() -> ptr +sig: file_stderr() -> pointer tip: The standard-error stream handle for use with file_write. order: 50 --- diff --git a/docs/language/builtins/fn-file_stdout.md b/docs/language/builtins/fn-file_stdout.md index 043e3985..421c8000 100644 --- a/docs/language/builtins/fn-file_stdout.md +++ b/docs/language/builtins/fn-file_stdout.md @@ -4,7 +4,7 @@ name: file_stdout category: builtins kind: builtin tokens: file_stdout -sig: file_stdout() -> ptr +sig: file_stdout() -> pointer tip: The standard-output stream handle for use with file_write. order: 50 --- diff --git a/docs/language/memory/memory-bytes.md b/docs/language/memory/memory-bytes.md index 1f0321d0..ab4b1c1b 100644 --- a/docs/language/memory/memory-bytes.md +++ b/docs/language/memory/memory-bytes.md @@ -4,7 +4,7 @@ name: Memory.bytes category: memory kind: namespace-method tokens: Memory.bytes -sig: Memory.bytes(n) -> ptr +sig: Memory.bytes(n) -> pointer tip: Allocate n bytes. order: 0 ns: Memory diff --git a/docs/language/operators/op-literals.md b/docs/language/operators/op-literals.md index 988377ce..0f0b5613 100644 --- a/docs/language/operators/op-literals.md +++ b/docs/language/operators/op-literals.md @@ -8,7 +8,7 @@ tip: Integer, hex, character, string, boolean, and null-pointer literals. order: 8 --- -Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `string`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `ptr` field. +Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `string`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `pointer` field. ```ludic let sky_color: int = 0x1E90FF diff --git a/docs/language/structure/kw-extern.md b/docs/language/structure/kw-extern.md index b397c60e..533ad8ee 100644 --- a/docs/language/structure/kw-extern.md +++ b/docs/language/structure/kw-extern.md @@ -9,7 +9,7 @@ tip: Bind a name to an external native symbol — the seam for platform and libr order: 12 --- -An extern function declares a function whose body lives outside Ludic and binds it to a native symbol resolved at link time. It is the seam through which Ludic reaches anything with a native interface — a system library, a math routine, or even another `.ludic` file compiled as a `module`. You write the Ludic signature you want to call and give the real symbol name after `=`; the linker connects them (pass `-L`/`-l` to `ludicc` to point at the library). Types must match the foreign ABI, so map each parameter and the return to the right Ludic type (`int`, `fixed`, `ptr`, …). +An extern function declares a function whose body lives outside Ludic and binds it to a native symbol resolved at link time. It is the seam through which Ludic reaches anything with a native interface — a system library, a math routine, or even another `.ludic` file compiled as a `module`. You write the Ludic signature you want to call and give the real symbol name after `=`; the linker connects them (pass `-L`/`-l` to `ludicc` to point at the library). Types must match the foreign ABI, so map each parameter and the return to the right Ludic type (`int`, `fixed`, `pointer`, …). Parameters: - `a` — a typed argument passed straight through to the foreign symbol diff --git a/docs/language/system/system-file_open.md b/docs/language/system/system-file_open.md index 538d2fda..08140eef 100644 --- a/docs/language/system/system-file_open.md +++ b/docs/language/system/system-file_open.md @@ -4,7 +4,7 @@ name: System.file_open category: system kind: namespace-method tokens: System.file_open -sig: System.file_open(path, mode) -> ptr +sig: System.file_open(path, mode) -> pointer tip: Open a file. order: 6 ns: System diff --git a/docs/language/system/system-stderr.md b/docs/language/system/system-stderr.md index 0f893343..9e645d6b 100644 --- a/docs/language/system/system-stderr.md +++ b/docs/language/system/system-stderr.md @@ -4,7 +4,7 @@ name: System.stderr category: system kind: namespace-method tokens: System.stderr -sig: System.stderr() -> ptr +sig: System.stderr() -> pointer tip: The standard error handle. order: 13 ns: System diff --git a/docs/language/system/system-stdout.md b/docs/language/system/system-stdout.md index e8657703..a080fa56 100644 --- a/docs/language/system/system-stdout.md +++ b/docs/language/system/system-stdout.md @@ -4,7 +4,7 @@ name: System.stdout category: system kind: namespace-method tokens: System.stdout -sig: System.stdout() -> ptr +sig: System.stdout() -> pointer tip: The standard output handle. order: 12 ns: System diff --git a/docs/language/types/type-byte.md b/docs/language/types/type-byte.md index 2a2b1cb8..e4e86c59 100644 --- a/docs/language/types/type-byte.md +++ b/docs/language/types/type-byte.md @@ -9,7 +9,7 @@ tip: A raw buffer indexed one byte at a time — each buffer[i] reads or writes order: 7 --- -`byte` is a raw buffer viewed one byte at a time: indexing `buffer[index]` reads or writes a single 8-bit value. It is the byte-sized view of the memory a `ptr` addresses — allocate it with `bytes(count)` and bind it as `byte` when you want per-byte access, for example to build up text, decode a file, or pack a compact grid. Each element is an `int` in the range of a byte. Like the other raw buffers it is unchecked, so you are responsible for staying in bounds. +`byte` is a raw buffer viewed one byte at a time: indexing `buffer[index]` reads or writes a single 8-bit value. It is the byte-sized view of the memory a `pointer` addresses — allocate it with `bytes(count)` and bind it as `byte` when you want per-byte access, for example to build up text, decode a file, or pack a compact grid. Each element is an `int` in the range of a byte. Like the other raw buffers it is unchecked, so you are responsible for staying in bounds. ```ludic let name_buffer: byte = bytes(16) diff --git a/docs/language/types/type-pointer.md b/docs/language/types/type-pointer.md new file mode 100644 index 00000000..1557f985 --- /dev/null +++ b/docs/language/types/type-pointer.md @@ -0,0 +1,18 @@ +--- +id: type-pointer +name: pointer +category: types +kind: type +tokens: pointer +sig: pointer +tip: A raw address into memory — a byte buffer from bytes(n), or an FFI handle. +order: 5 +--- + +`pointer` is a raw address into memory — the low-level type for runtime and foreign-function work, not something an everyday game reaches for. Allocate a raw byte buffer with `bytes(count)`, which returns a `pointer` you index as `buffer[index]` to read or write one byte; retype the binding as `words` / `fixeds` / `pointers` to index in larger element sizes. A `pointer` is also how an `extern function` passes an opaque C handle across the ABI. Test one for emptiness against the `null` literal. + +```ludic +let scratch: pointer = bytes(256) +scratch[0] = 65 +if scratch != null { scratch[1] = 66 } +``` diff --git a/docs/language/types/type-pointers.md b/docs/language/types/type-pointers.md new file mode 100644 index 00000000..7f28c651 --- /dev/null +++ b/docs/language/types/type-pointers.md @@ -0,0 +1,25 @@ +--- +id: type-pointers +name: pointers +category: types +kind: type +tokens: pointers +sig: pointers +tip: A buffer of pointers — p[i] reads and writes a pointer. +order: 9 +--- + +A pointers is a raw buffer whose elements are pointers: index it with buffer[i] to read or write a pointer, with no bounds checking. Allocate the storage with words(n) (a pointer fits in a slot) and type the binding as pointers so indexing uses the pointer element size. It is the low-level building block for hand-rolled data structures — a table of records made with new, a free list, a bucket array — for when you want manual control instead of a growable []T slice. + +```ludic +program Records { + property Position { column: int = 0, row: int = 0 } + + handler Setup phase Start { + let slots: pointers = words(2) + slots[0] = new Position + slots[1] = new Position + print(2) + } +} +``` diff --git a/docs/language/types/type-ptr.md b/docs/language/types/type-ptr.md deleted file mode 100644 index fb36276c..00000000 --- a/docs/language/types/type-ptr.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: type-ptr -name: ptr -category: types -kind: type -tokens: ptr -sig: ptr -tip: A raw address into memory — a byte buffer from bytes(n), or an FFI handle. -order: 5 ---- - -`ptr` is a raw address into memory — the low-level type for runtime and foreign-function work, not something an everyday game reaches for. Allocate a raw byte buffer with `bytes(count)`, which returns a `ptr` you index as `buffer[index]` to read or write one byte; retype the binding as `words` / `fixeds` / `ptrs` to index in larger element sizes. A `ptr` is also how an `extern function` passes an opaque C handle across the ABI. Test one for emptiness against the `null` literal. - -```ludic -let scratch: ptr = bytes(256) -scratch[0] = 65 -if scratch != null { scratch[1] = 66 } -``` diff --git a/docs/language/types/type-ptrs.md b/docs/language/types/type-ptrs.md deleted file mode 100644 index 106d6e42..00000000 --- a/docs/language/types/type-ptrs.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -id: type-ptrs -name: ptrs -category: types -kind: type -tokens: ptrs -sig: ptrs -tip: A buffer of pointers — p[i] reads and writes a ptr. -order: 9 ---- - -A ptrs is a raw buffer whose elements are pointers: index it with buffer[i] to read or write a ptr, with no bounds checking. Allocate the storage with words(n) (a pointer fits in a slot) and type the binding as ptrs so indexing uses the pointer element size. It is the low-level building block for hand-rolled data structures — a table of records made with new, a free list, a bucket array — for when you want manual control instead of a growable []T slice. - -```ludic -program Records { - property Position { column: int = 0, row: int = 0 } - - handler Setup phase Start { - let slots: ptrs = words(2) - slots[0] = new Position - slots[1] = new Position - print(2) - } -} -``` diff --git a/docs/language/types/type-words.md b/docs/language/types/type-words.md index ea950594..f69a67c4 100644 --- a/docs/language/types/type-words.md +++ b/docs/language/types/type-words.md @@ -9,7 +9,7 @@ tip: A raw buffer indexed as 32-bit words — each buffer[i] reads or writes an order: 6 --- -`words` is a raw buffer viewed as a sequence of 32-bit words: indexing `buffer[index]` reads or writes one `int`. It is the same underlying memory a `ptr` addresses, retyped so the element size is a word instead of a byte — allocate the storage with `words(count)` (count 32-bit words) and bind it as `words` to index it that way. Reach for it when you need a flat integer array outside the ECS — a lookup table, a scratch grid — and want plain integer indexing without the growable-slice header. Like all raw buffers it is unbounded and unchecked, so keep your own length. +`words` is a raw buffer viewed as a sequence of 32-bit words: indexing `buffer[index]` reads or writes one `int`. It is the same underlying memory a `pointer` addresses, retyped so the element size is a word instead of a byte — allocate the storage with `words(count)` (count 32-bit words) and bind it as `words` to index it that way. Reach for it when you need a flat integer array outside the ECS — a lookup table, a scratch grid — and want plain integer indexing without the growable-slice header. Like all raw buffers it is unbounded and unchecked, so keep your own length. ```ludic let height_map: words = words(64) diff --git a/examples/world_mixed.ludic b/examples/world_mixed.ludic index fc37f7d0..d9d0d2c5 100644 --- a/examples/world_mixed.ludic +++ b/examples/world_mixed.ludic @@ -3,7 +3,7 @@ # a `ptr` field, so its byte offset is 8, not 4; writing qty=99 by name and reading # it back proves the world table addresses fields by their true layout. Prints 99. program WorldMixed { - property Slot { ref: ptr = null, qty: int = 0 } + property Slot { ref: pointer = null, qty: int = 0 } model Item { Slot } @Public @OnSpawn(Item) handler Born { } # makes it a modding program diff --git a/runtime/native/core.ludic b/runtime/native/core.ludic index fa458800..8b7f4259 100644 --- a/runtime/native/core.ludic +++ b/runtime/native/core.ludic @@ -329,7 +329,7 @@ function rt_running() -> bool { } # ---- writing the frame out ------------------------------------------------ -function rt_put_str(buf: ptr, at: int, s: string) -> int { +function rt_put_str(buf: pointer, at: int, s: string) -> int { var i = 0 var n = at var ch = s[0] @@ -342,7 +342,7 @@ function rt_put_str(buf: ptr, at: int, s: string) -> int { return n } -function rt_put_int(buf: ptr, at: int, v: int) -> int { +function rt_put_int(buf: pointer, at: int, v: int) -> int { if v == 0 { buf[at] = 48 return at + 1 @@ -402,7 +402,7 @@ import "ui.ludic" # A character grid the game paints with map_row() and reads with tile(). Stored # as one byte per cell in a flat buffer; out-of-bounds reads answer '#' so a # caller can treat the edge of the world as wall without special-casing it. -var rt_map: ptr = null +var rt_map: pointer = null var rt_mapw: int = 0 var rt_maph: int = 0 @@ -436,7 +436,7 @@ function rt_tile(x: int, y: int) -> int { # ---- status line ---------------------------------------------------------- # One persistent string of feedback/dialogue, copied into runtime-owned memory # so it survives whatever the caller does with the original. -var rt_statusbuf: ptr = null +var rt_statusbuf: pointer = null function rt_status(s: string) -> void { var i = 0 @@ -452,7 +452,7 @@ function rt_status(s: string) -> void { rt_statusbuf[i] = 0 } -function rt_status_text() -> ptr { +function rt_status_text() -> pointer { return rt_statusbuf } @@ -460,7 +460,7 @@ function rt_status_text() -> ptr { # The compiler writes the ECS (entities, components, archetype kinds) because # only it knows their shape. Everything below belongs to the runtime, so the # runtime writes it — same order both ways. -function rt_save_state(f: ptr) -> void { +function rt_save_state(f: pointer) -> void { let w: words = bytes(16) w[0] = rt_rng w[1] = rt_mapw @@ -473,7 +473,7 @@ function rt_save_state(f: ptr) -> void { free(w) } -function rt_load_state(f: ptr) -> void { +function rt_load_state(f: pointer) -> void { let w: words = bytes(16) file_read(f, w, 16) rt_rng = w[0] diff --git a/runtime/native/image.ludic b/runtime/native/image.ludic index 16360f28..c672f49f 100644 --- a/runtime/native/image.ludic +++ b/runtime/native/image.ludic @@ -13,7 +13,7 @@ const IMG_MAX: int = 32 const SPR_MAX: int = 160 const SPR_SZ: int = 16 -var img_px: ptrs = null # IMG_MAX pointers to RGBA buffers +var img_px: pointers = null # IMG_MAX pointers to RGBA buffers var img_w: words = null var img_h: words = null var img_n: int = 0 @@ -30,11 +30,11 @@ function rt_image_init() -> void { } # ---- decoding ------------------------------------------------------------- -function png_be32(b: ptr, at: int) -> int { +function png_be32(b: pointer, at: int) -> int { return (b[at] << 24) | (b[at + 1] << 16) | (b[at + 2] << 8) | b[at + 3] } -function png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool { +function png_tag(b: pointer, at: int, a: int, c: int, d: int, e: int) -> bool { if b[at] != a { return false } if b[at + 1] != c { return false } if b[at + 2] != d { return false } @@ -42,7 +42,7 @@ function png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool { return true } -function rt_read_file(path: string) -> ptr { +function rt_read_file(path: string) -> pointer { let f = file_open(path, "rb") if (f == null) { return null } file_seek(f, 0, 2) diff --git a/runtime/native/inflate.ludic b/runtime/native/inflate.ludic index 094d2f1c..e4ace50c 100644 --- a/runtime/native/inflate.ludic +++ b/runtime/native/inflate.ludic @@ -13,14 +13,14 @@ # ============================================================================ # ---- bit reader (DEFLATE packs bits least-significant-first) --------------- -var z_src: ptr = null +var z_src: pointer = null var z_len: int = 0 var z_pos: int = 0 var z_bitbuf: int = 0 var z_bitcnt: int = 0 var z_err: int = 0 -function z_start(src: ptr, len: int) -> void { +function z_start(src: pointer, len: int) -> void { z_src = src z_len = len z_pos = 0 @@ -48,7 +48,7 @@ function z_bits(need: int) -> int { # ---- Huffman tables ------------------------------------------------------- # A table is a single buffer: 16 length-counts followed by the symbols in # canonical order. One allocation, no structs. -function z_table_new(nsym: int) -> ptr { +function z_table_new(nsym: int) -> pointer { return words((16 + nsym)) } @@ -125,7 +125,7 @@ function z_dist_extra(sym: int) -> int { # ---- block decoders ------------------------------------------------------- # `out` is the destination window; returns the new write position, or -1. -function z_stored(out: ptr, at: int, cap: int) -> int { +function z_stored(out: pointer, at: int, cap: int) -> int { z_bitbuf = 0 z_bitcnt = 0 # stored blocks are byte-aligned if z_pos + 4 > z_len { return -1 } @@ -142,7 +142,7 @@ function z_stored(out: ptr, at: int, cap: int) -> int { return w } -function z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int { +function z_codes(out: pointer, at: int, cap: int, lit: pointer, dist: pointer) -> int { var w = at var sym = z_decode(lit) while sym != 256 { @@ -172,7 +172,7 @@ function z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int { return w } -function z_fixed_tables(lit: ptr, dist: ptr) -> void { +function z_fixed_tables(lit: pointer, dist: pointer) -> void { let lengths: words = words(288) for i in 0 .. 144 { lengths[i] = 8 } for i in 144 .. 256 { lengths[i] = 9 } @@ -184,7 +184,7 @@ function z_fixed_tables(lit: ptr, dist: ptr) -> void { free(lengths) } -function z_dynamic_tables(lit: ptr, dist: ptr) -> int { +function z_dynamic_tables(lit: pointer, dist: pointer) -> int { let nlen = z_bits(5) + 257 let ndist = z_bits(5) + 1 let ncode = z_bits(4) + 4 @@ -240,7 +240,7 @@ function z_dynamic_tables(lit: ptr, dist: ptr) -> int { } # Inflate a raw DEFLATE stream. Returns bytes written, or -1. -function z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int { +function z_inflate(src: pointer, len: int, out: pointer, cap: int) -> int { z_start(src, len) let lit = z_table_new(288) let dist = z_table_new(30) @@ -268,7 +268,7 @@ function z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int { } # zlib wrapper (RFC 1950): two header bytes, then DEFLATE, then Adler-32. -function z_uncompress(src: ptr, len: int, out: ptr, cap: int) -> int { +function z_uncompress(src: pointer, len: int, out: pointer, cap: int) -> int { if len < 2 { return -1 } let cmf = src[0] if (cmf & 15) != 8 { return -1 } diff --git a/runtime/native/truetype.ludic b/runtime/native/truetype.ludic index 2655d053..67323454 100644 --- a/runtime/native/truetype.ludic +++ b/runtime/native/truetype.ludic @@ -18,7 +18,7 @@ const TT_EDGES: int = 16384 # line segments in one glyph const TT_GC: int = 512 # glyph cache entries # ---- per-font tables (parallel arrays; index = font id) ------------------- -var tt_data: ptrs = null +var tt_data: pointers = null var tt_size: words = null var tt_upem: words = null var tt_nglyf: words = null @@ -61,7 +61,7 @@ var gc_h: words = null var gc_ox: words = null var gc_oy: words = null var gc_adv: words = null -var gc_bmp: ptrs = null +var gc_bmp: pointers = null function rt_tt_init() -> void { tt_data = bytes(TT_MAX * 8) @@ -105,24 +105,24 @@ function rt_tt_init() -> void { } # ---- big-endian readers --------------------------------------------------- -function tt_u16(d: ptr, at: int) -> int { +function tt_u16(d: pointer, at: int) -> int { return ((d[at] << 8) | d[at + 1]) } -function tt_i16(d: ptr, at: int) -> int { +function tt_i16(d: pointer, at: int) -> int { let v = tt_u16(d, at) if v >= 32768 { return v - 65536 } return v } -function tt_u32(d: ptr, at: int) -> int { +function tt_u32(d: pointer, at: int) -> int { return (d[at] << 24) | (d[at + 1] << 16) | (d[at + 2] << 8) | d[at + 3] } -function tt_i8(d: ptr, at: int) -> int { +function tt_i8(d: pointer, at: int) -> int { let v = d[at] if v >= 128 { return v - 256 } return v } -function tt_find_table(d: ptr, base: int, a: int, b: int, c: int, e: int) -> int { +function tt_find_table(d: pointer, base: int, a: int, b: int, c: int, e: int) -> int { let n = tt_u16(d, base + 4) for i in 0 .. n { let rec = base + 12 + i * 16 @@ -138,7 +138,7 @@ function tt_find_table(d: ptr, base: int, a: int, b: int, c: int, e: int) -> int } # pick the most capable Unicode subtable, as the C loader did -function tt_pick_cmap(id: int, d: ptr, co: int) -> void { +function tt_pick_cmap(id: int, d: pointer, co: int) -> void { tt_cmap[id] = 0 - 1 tt_cfmt[id] = 0 if co < 0 { return } diff --git a/runtime/native/truetype_raster.ludic b/runtime/native/truetype_raster.ludic index 74237ea6..fc31d52c 100644 --- a/runtime/native/truetype_raster.ludic +++ b/runtime/native/truetype_raster.ludic @@ -51,7 +51,7 @@ var gr_ox: int = 0 var gr_oy: int = 0 var gr_adv: int = 0 -function tt_raster(id: int, gid: int, px: int) -> ptr { +function tt_raster(id: int, gid: int, px: int) -> pointer { let upem = tt_upem[id] let scale = fx(px) / upem gr_adv = flr(fx(tt_advance(id, gid)) * scale + 0.5) @@ -298,7 +298,7 @@ function tt_utf8(s: string, at: int) -> int { } # ---- drawing -------------------------------------------------------------- -function tt_blit(bmp: ptr, w: int, h: int, dx: int, dy: int, colour: int) -> void { +function tt_blit(bmp: pointer, w: int, h: int, dx: int, dy: int, colour: int) -> void { if (bmp == null) { return } let cr = ((colour >> 16) & 255) let cg = ((colour >> 8) & 255) diff --git a/runtime/native/ui.ludic b/runtime/native/ui.ludic index 27bbc18f..97b16ebe 100644 --- a/runtime/native/ui.ludic +++ b/runtime/native/ui.ludic @@ -72,8 +72,8 @@ var ui_rh: words = null var ui_visible: words = null var ui_fired: words = null var ui_hasdyn: words = null -var ui_dyn: ptr = null # UI_MAX * 96 bytes -var ui_text: ptrs = null # UI_MAX static string pointers +var ui_dyn: pointer = null # UI_MAX * 96 bytes +var ui_text: pointers = null # UI_MAX static string pointers var ui_n: int = 0 var ui_active: int = -1 @@ -175,14 +175,14 @@ function rt_ui_static_text(i: int, s: string) -> void { } # ---- text helpers: TrueType when a font is loaded, bitmap otherwise ------- -function ui_str(i: int) -> ptr { +function ui_str(i: int) -> pointer { if ui_hasdyn[i] == 1 { return offset(ui_dyn, i * 96) } let t = ui_text[i] if (t == null) { return offset(ui_dyn, i * 96) } return t } -function ui_draw_text(font: int, x: int, y: int, s: ptr, colour: int, size: int) -> void { +function ui_draw_text(font: int, x: int, y: int, s: pointer, colour: int, size: int) -> void { if font >= 0 { if font < tt_n { rt_text_ttf(font, x, y, s, colour, size) @@ -192,7 +192,7 @@ function ui_draw_text(font: int, x: int, y: int, s: ptr, colour: int, size: int) rt_text(x, y, s, colour, max(size / 8, 1)) } -function ui_tw(font: int, s: ptr, size: int) -> int { +function ui_tw(font: int, s: pointer, size: int) -> int { if font >= 0 { if font < tt_n { return rt_text_w(font, s, size) } } diff --git a/selfhost/ast.ludic b/selfhost/ast.ludic index 26a0b6c3..9f9eb98f 100644 --- a/selfhost/ast.ludic +++ b/selfhost/ast.ludic @@ -66,9 +66,9 @@ const E_SLICE: int = 44 # s[a..b] — substring (a=base, b=start, c=end property Node { kind: int = 0 - s: ptr = null # name / operator / string / type-of-new + s: pointer = null # name / operator / string / type-of-new ival: int = 0 # int literal, bool, flags - ty: ptr = null # declared type (let/param/field/fn/var/const) + ty: pointer = null # declared type (let/param/field/fn/var/const) a: Node # fixed children (meaning per kind) b: Node c: Node diff --git a/selfhost/buf.ludic b/selfhost/buf.ludic index 4ae05666..a17e534c 100644 --- a/selfhost/buf.ludic +++ b/selfhost/buf.ludic @@ -2,7 +2,7 @@ # module-level material (types, globals, string constants) into one buffer and # function bodies into another, then prints them in order. -property Buf { data: ptr = null, len: int = 0, cap: int = 0 } +property Buf { data: pointer = null, len: int = 0, cap: int = 0 } function buf_new() -> Buf { let b = new Buf @@ -21,9 +21,9 @@ function buf_putc(b: Buf, c: int) -> void { b.data[b.len] = c b.len = b.len + 1 } -function buf_puts(b: Buf, s: ptr) -> void { +function buf_puts(b: Buf, s: pointer) -> void { var i = 0 while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 } } function buf_puti(b: Buf, n: int) -> void { buf_puts(b, itoa(n)) } -function buf_str(b: Buf) -> ptr { b.data[b.len] = 0; return b.data } +function buf_str(b: Buf) -> pointer { b.data[b.len] = 0; return b.data } diff --git a/selfhost/emit_addr.ludic b/selfhost/emit_addr.ludic index a8c38543..2c4cd2cf 100644 --- a/selfhost/emit_addr.ludic +++ b/selfhost/emit_addr.ludic @@ -2,10 +2,10 @@ # shared by expression loads and assignment stores. Each returns the address # register; the element/field type is written into g_addr_ty. -var g_addr_ty: ptr # out-param: the type at the computed address +var g_addr_ty: pointer # out-param: the type at the computed address # address of `base.field` -function emit_member_addr(e: Node) -> ptr { +function emit_member_addr(e: Node) -> pointer { let base = emit_expr(e.a) let s = layout_node(base.ty) if (s == null) { perr(`member access on non-aggregate {base.ty}`) } @@ -19,7 +19,7 @@ function emit_member_addr(e: Node) -> ptr { } # address of `base[index]` (slices only in this subset) -function emit_index_addr(e: Node) -> ptr { +function emit_index_addr(e: Node) -> pointer { let base = emit_expr(e.a) if not is_slice_ty(base.ty) { # a raw pointer: address of element i let bi = emit_expr(e.b) # (evaluate index first — it may set g_addr_ty) @@ -33,7 +33,7 @@ function emit_index_addr(e: Node) -> ptr { g_addr_ty = "fixed" return rf } - if (base.ty == "ptrs") { # a `ptrs` buffer: pointer elements + if (base.ty == "pointers") { # a `pointers` buffer: pointer elements let rp = emit_bind(`getelementptr inbounds ptr, ptr {base.code}, i32 {bi.code}`) g_addr_ty = "ptr" return rp diff --git a/selfhost/emit_collide.ludic b/selfhost/emit_collide.ludic index 04651a2f..0d14f2a4 100644 --- a/selfhost/emit_collide.ludic +++ b/selfhost/emit_collide.ludic @@ -3,14 +3,14 @@ # origin at the top-left; circles are (x, y, r). Squared distances use i64 so a # large coordinate can't overflow. Each returns a bool. -function is_collide_ns(meth: ptr) -> bool { +function is_collide_ns(meth: pointer) -> bool { if (meth == "rects") or (meth == "point_rect") { return true } if (meth == "circles") or (meth == "rect_circle") { return true } return false } # dx*dx + dy*dy widened to i64 (no overflow for 32-bit deltas) -function coll_sq_sum(dx: ptr, dy: ptr) -> ptr { +function coll_sq_sum(dx: pointer, dy: pointer) -> pointer { let dx64 = emit_bind(`sext i32 {dx} to i64`) let dy64 = emit_bind(`sext i32 {dy} to i64`) let xx = emit_bind(`mul i64 {dx64}, {dx64}`) @@ -19,14 +19,14 @@ function coll_sq_sum(dx: ptr, dy: ptr) -> ptr { } # max(lo, min(v, hi)) — clamp v into [lo, hi] -function coll_clamp(v: ptr, lo: ptr, hi: ptr) -> ptr { +function coll_clamp(v: pointer, lo: pointer, hi: pointer) -> pointer { let c1 = emit_bind(`icmp slt i32 {v}, {hi}`) let t = emit_bind(`select i1 {c1}, i32 {v}, i32 {hi}`) let c2 = emit_bind(`icmp sgt i32 {lo}, {t}`) return emit_bind(`select i1 {c2}, i32 {lo}, i32 {t}`) } -function emit_collide_ns(meth: ptr, e: Node) -> Val { +function emit_collide_ns(meth: pointer, e: Node) -> Val { if (meth == "rects") { # AABB overlap of two rects let ax = emit_expr(e.kids[0]); let ay = emit_expr(e.kids[1]); let aw = emit_expr(e.kids[2]); let ah = emit_expr(e.kids[3]) let bx = emit_expr(e.kids[4]); let by = emit_expr(e.kids[5]); let bw = emit_expr(e.kids[6]); let bh = emit_expr(e.kids[7]) diff --git a/selfhost/emit_color.ludic b/selfhost/emit_color.ludic index cb1f8c74..8c3f2b0f 100644 --- a/selfhost/emit_color.ludic +++ b/selfhost/emit_color.ludic @@ -9,7 +9,7 @@ # Edit the palette there and regenerate; do not hand-edit this file. # ============================================================================ -function color_lookup(name: ptr) -> int { +function color_lookup(name: pointer) -> int { if (name == "White") { return 0xFFFFFF } if (name == "Snow") { return 0xFFFAFA } if (name == "Ivory") { return 0xFFFFF0 } diff --git a/selfhost/emit_colorfn.ludic b/selfhost/emit_colorfn.ludic index e76f1b8c..ea71e80c 100644 --- a/selfhost/emit_colorfn.ludic +++ b/selfhost/emit_colorfn.ludic @@ -3,20 +3,20 @@ # and blend them with plain integer/fixed math. rgb/rgba pack channels; lerp/ # darken/lighten/with_alpha transform an existing color. -function is_colorfn_ns(meth: ptr) -> bool { +function is_colorfn_ns(meth: pointer) -> bool { if (meth == "rgb") or (meth == "rgba") or (meth == "lerp") { return true } if (meth == "darken") or (meth == "lighten") or (meth == "with_alpha") { return true } return false } # (c >> shift) & 255 -> code of a channel value -function color_ch(c: ptr, shift: ptr) -> ptr { +function color_ch(c: pointer, shift: pointer) -> pointer { let sh = emit_bind(`lshr i32 {c}, {shift}`) return emit_bind(`and i32 {sh}, 255`) } # (r << 16) | (g << 8) | b -> code of a packed color -function color_pack(r: ptr, g: ptr, b: ptr) -> ptr { +function color_pack(r: pointer, g: pointer, b: pointer) -> pointer { let r16 = emit_bind(`shl i32 {r}, 16`) let g8 = emit_bind(`shl i32 {g}, 8`) let rg = emit_bind(`or i32 {r16}, {g8}`) @@ -24,14 +24,14 @@ function color_pack(r: ptr, g: ptr, b: ptr) -> ptr { } # ch0 + ((ch1 - ch0) * t >> 16), t a fixed 0..1 -> code of a blended channel -function color_lerp_ch(ch0: ptr, ch1: ptr, t: ptr) -> ptr { +function color_lerp_ch(ch0: pointer, ch1: pointer, t: pointer) -> pointer { let d = emit_bind(`sub i32 {ch1}, {ch0}`) let dt = emit_bind(`mul i32 {d}, {t}`) let dsh = emit_bind(`ashr i32 {dt}, 16`) return emit_bind(`add i32 {ch0}, {dsh}`) } -function emit_colorfn_ns(meth: ptr, e: Node) -> Val { +function emit_colorfn_ns(meth: pointer, e: Node) -> Val { if (meth == "rgb") { # rgb(r, g, b) -> 0xRRGGBB let r = emit_expr(e.kids[0]); let g = emit_expr(e.kids[1]); let b = emit_expr(e.kids[2]) return val(color_pack(r.code, g.code, b.code), "int") diff --git a/selfhost/emit_core.ludic b/selfhost/emit_core.ludic index bf1ae345..bfc283b8 100644 --- a/selfhost/emit_core.ludic +++ b/selfhost/emit_core.ludic @@ -2,8 +2,8 @@ # module header. Mirrors the pieces of compiler/back/ that this subset needs. # structs and slices are references, so every non-scalar type lowers to `ptr`. -property Val { code: ptr = null, ty: ptr = null } -function val(code: ptr, ty: ptr) -> Val { let v = new Val; v.code = code; v.ty = ty; return v } +property Val { code: pointer = null, ty: pointer = null } +function val(code: pointer, ty: pointer) -> Val { let v = new Val; v.code = code; v.ty = ty; return v } var head: Buf # module-level: types, globals, string constants var code: Buf # function bodies @@ -13,9 +13,9 @@ var ll_lbl: int = 0 # label counter var ll_str: int = 0 # string-constant counter # local environment (parallel slices), reset per function -var loc_name: []ptr -var loc_reg: []ptr -var loc_ty: []ptr +var loc_name: []pointer +var loc_reg: []pointer +var loc_ty: []pointer var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let) var nloc: int = 0 var g_uses_str: bool = false # a `str + str` / `str == str` was emitted -> emit the prelude @@ -28,13 +28,13 @@ var g_uses_hashrt: bool = false # Hash.of/fnv1a/crc32 was emitted -> emit the b var g_uses_longstr: bool = false # string(long) / interpolating a long was emitted -> emit fn_long_str # loop targets for break/continue (innermost last) -var brk_lbl: []ptr -var cnt_lbl: []ptr +var brk_lbl: []pointer +var cnt_lbl: []pointer var nloop: int = 0 -var ret_ty: ptr # current function's return type +var ret_ty: pointer # current function's return type var g_term: bool = false # did the current block end in a terminator? -var self_stk: []ptr # entity-index slot (ip) per enclosing query, for self() +var self_stk: []pointer # entity-index slot (ip) per enclosing query, for self() var nself: int = 0 var mach_stk: []Node # enclosing `machine` nodes, so `become` finds its register var nmach: int = 0 @@ -47,69 +47,69 @@ var g_scene_count: int = 0 # parse-time id counter var g_start_scene: int = 0 # id of the scene marked `start` (else the first) var g_cur_scene: Node = null # scene owning the handler being emitted, for `become` -function find_scene(name: ptr) -> Node { +function find_scene(name: pointer) -> Node { var i = 0 while i < len(g_scenes) { if (g_scenes[i].s == name) { return g_scenes[i] }; i = i + 1 } return null } -function emit(s: ptr) -> void { buf_puts(code, s) } -function emith(s: ptr) -> void { buf_puts(head, s) } +function emit(s: pointer) -> void { buf_puts(code, s) } +function emith(s: pointer) -> void { buf_puts(head, s) } # stack slots MUST live in the entry block (an alloca in a loop walks the stack # off its end), so they go into a per-function buffer spliced in at entry. -function emit_alloca(llt: ptr) -> ptr { +function emit_alloca(llt: pointer) -> pointer { let r = `%t{itoa(ll_t)}`; ll_t = ll_t + 1 buf_puts(falloc, " "); buf_puts(falloc, r); buf_puts(falloc, " = alloca "); buf_puts(falloc, llt); buf_puts(falloc, "\n") return r } # "%t" fresh register -function nreg() -> ptr { let r = `%t{itoa(ll_t)}`; ll_t = ll_t + 1; return r } -function lbl(pfx: ptr) -> ptr { let r = (pfx + itoa(ll_lbl)); ll_lbl = ll_lbl + 1; return r } +function nreg() -> pointer { let r = `%t{itoa(ll_t)}`; ll_t = ll_t + 1; return r } +function lbl(pfx: pointer) -> pointer { let r = (pfx + itoa(ll_lbl)); ll_lbl = ll_lbl + 1; return r } # Ludic type -> LLVM type. int/bool are i32; everything else (ptr/str/struct/ # slice) is a pointer; void is void. -function llty(t: ptr) -> ptr { +function llty(t: pointer) -> pointer { if (t == "int") or (t == "bool") or (t == "fixed") or (t == "entity") { return "i32" } # entity = an i32 handle (self()) if (t == "long") { return "i64" } # a 64-bit signed integer if (t == "byte") { return "i8" } # a single byte (p[i] on a raw ptr) - if (t == "words") or (t == "fixeds") or (t == "ptrs") { return "ptr" } # typed buffers + if (t == "words") or (t == "fixeds") or (t == "pointers") { return "ptr" } # typed buffers if (t == "void") { return "void" } return "ptr" } -function is_slice_ty(t: ptr) -> bool { return t[0] == 91 and t[1] == 93 } # "[]" -function slice_elem(t: ptr) -> ptr { return t[2..len(t)] } +function is_slice_ty(t: pointer) -> bool { return t[0] == 91 and t[1] == 93 } # "[]" +function slice_elem(t: pointer) -> pointer { return t[2..len(t)] } -function find_arch(name: ptr) -> Node { +function find_arch(name: pointer) -> Node { var i = 0 while i < len(prog) { let d = prog[i]; if d.kind == N_ARCH and (d.s == name) { return d }; i = i + 1 } return null } -function find_comp(name: ptr) -> Node { +function find_comp(name: pointer) -> Node { var i = 0 while i < len(prog) { let d = prog[i]; if d.kind == N_COMP and (d.s == name) { return d }; i = i + 1 } return null } # every record is a `property` with a %Cmp_ layout of named fields — whether it # is stored per-entity by the ECS or heap-allocated by `new` is a matter of use. -function layout_node(name: ptr) -> Node { return find_comp(name) } -function layout_ty(name: ptr) -> ptr { return (("%Cmp_") + name) } +function layout_node(name: pointer) -> Node { return find_comp(name) } +function layout_ty(name: pointer) -> pointer { return (("%Cmp_") + name) } -function field_index(s: Node, fname: ptr) -> int { +function field_index(s: Node, fname: pointer) -> int { var i = 0 while i < len(s.kids) { if (s.kids[i].s == fname) { return i }; i = i + 1 } return 0 - 1 } -function field_type(s: Node, fname: ptr) -> ptr { +function field_type(s: Node, fname: pointer) -> pointer { var i = 0 while i < len(s.kids) { if (s.kids[i].s == fname) { return s.kids[i].ty }; i = i + 1 } return "int" } # find a global var/const by name -function find_global(name: ptr) -> Node { +function find_global(name: pointer) -> Node { var i = 0 while i < len(prog) { let d = prog[i] @@ -122,7 +122,7 @@ function find_global(name: ptr) -> Node { # `Enum.Variant` -> the variant's ordinal (its index), or -1 if `ename` names no # enum with that variant. Enum names live in `prog` like any other declaration. -function enum_ordinal(ename: ptr, vname: ptr) -> int { +function enum_ordinal(ename: pointer, vname: pointer) -> int { var i = 0 while i < len(prog) { let d = prog[i] @@ -141,7 +141,7 @@ function enum_ordinal(ename: ptr, vname: ptr) -> int { } return 0 - 1 } -function find_fn(name: ptr) -> Node { +function find_fn(name: pointer) -> Node { var i = 0 while i < len(prog) { let d = prog[i]; if d.kind == N_FN and (d.s == name) { return d }; i = i + 1 } return null @@ -152,7 +152,7 @@ function find_fn(name: ptr) -> Node { # the exact linked symbol), and emit_extern_decls emits a matching `declare`. This # is the transport seam (net_send/net_poll), the windowing/socket FFI, and any # C/Rust/Zig library binding — the same seam NETWORKING-DESIGN §5 names. -function find_extern(name: ptr) -> Node { +function find_extern(name: pointer) -> Node { var i = 0 while i < len(prog) { let d = prog[i]; if d.kind == N_EXTERN and (d.s == name) { return d }; i = i + 1 } return null @@ -163,11 +163,11 @@ function find_extern(name: ptr) -> Node { # expression with its bare names read as fields of `x`. Populated at parse time. var g_computed: []Node # each: s = "Prop.field", ty = result type, a = expr -function register_computed(prop: ptr, field: ptr, ty: ptr, e: Node) -> void { +function register_computed(prop: pointer, field: pointer, ty: pointer, e: Node) -> void { let cf = node(N_FIELD); cf.s = `{prop}.{field}`; cf.ty = ty; cf.a = e push(g_computed, cf) } -function computed_expr(prop: ptr, field: ptr) -> Node { +function computed_expr(prop: pointer, field: pointer) -> Node { if (prop == null) { return null } let key = `{prop}.{field}` var i = 0 @@ -175,7 +175,7 @@ function computed_expr(prop: ptr, field: ptr) -> Node { return null } # best-effort static type of an expression (for computed-field lookup; emits nothing) -function static_type(e: Node) -> ptr { +function static_type(e: Node) -> pointer { if e.kind == E_ID { let li = loc_find(e.s); if li >= 0 { return loc_ty[li] } } return null } @@ -185,10 +185,10 @@ function static_type(e: Node) -> ptr { # constructor). Spawn statically knows the model, so no runtime dispatch is needed. var g_onspawn: []Node # each: s = Model name, a = hook body block -function register_onspawn(model: ptr, body: Node) -> void { +function register_onspawn(model: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = model; n.a = body; push(g_onspawn, n) } -function onspawn_body(model: ptr) -> Node { +function onspawn_body(model: pointer) -> Node { var i = 0 while i < len(g_onspawn) { if (g_onspawn[i].s == model) { return g_onspawn[i].a }; i = i + 1 } return null @@ -203,18 +203,18 @@ var g_onattach: []Node # each: s = Property name, a = hook body block # LC1: `.ty` carries the optional `reason:` binding name (null if the hook took # no reason). The despawn hook function gains an `i32 %reason` parameter and each # teardown site passes a constant EndReason (see emit_despawn_hooks / emit_despawn). -function register_ondespawn(model: ptr, body: Node, reason: ptr) -> void { +function register_ondespawn(model: pointer, body: Node, reason: pointer) -> void { let n = node(N_BLOCK); n.s = model; n.a = body; n.ty = reason; push(g_ondespawn, n) } -function ondespawn_body(model: ptr) -> Node { +function ondespawn_body(model: pointer) -> Node { var i = 0 while i < len(g_ondespawn) { if (g_ondespawn[i].s == model) { return g_ondespawn[i].a }; i = i + 1 } return null } -function register_onattach(prop: ptr, body: Node) -> void { +function register_onattach(prop: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_onattach, n) } -function onattach_body(prop: ptr) -> Node { +function onattach_body(prop: pointer) -> Node { var i = 0 while i < len(g_onattach) { if (g_onattach[i].s == prop) { return g_onattach[i].a }; i = i + 1 } return null @@ -224,10 +224,10 @@ function onattach_body(prop: ptr) -> Node { # is removed from a live entity (`detach P on e`), with the property bound by name # so the body can read its outgoing value before it is cleared. var g_ondetach: []Node # each: s = Property name, a = hook body block -function register_ondetach(prop: ptr, body: Node) -> void { +function register_ondetach(prop: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_ondetach, n) } -function ondetach_body(prop: ptr) -> Node { +function ondetach_body(prop: pointer) -> Node { var i = 0 while i < len(g_ondetach) { if (g_ondetach[i].s == prop) { return g_ondetach[i].a }; i = i + 1 } return null @@ -237,14 +237,14 @@ function ondetach_body(prop: ptr) -> Node { # entity, with the property bound by name. var g_onenable: []Node var g_ondisable: []Node -function register_onenable(prop: ptr, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_onenable, n) } -function register_ondisable(prop: ptr, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_ondisable, n) } -function onenable_body(prop: ptr) -> Node { +function register_onenable(prop: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_onenable, n) } +function register_ondisable(prop: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_ondisable, n) } +function onenable_body(prop: pointer) -> Node { var i = 0 while i < len(g_onenable) { if (g_onenable[i].s == prop) { return g_onenable[i].a }; i = i + 1 } return null } -function ondisable_body(prop: ptr) -> Node { +function ondisable_body(prop: pointer) -> Node { var i = 0 while i < len(g_ondisable) { if (g_ondisable[i].s == prop) { return g_ondisable[i].a }; i = i + 1 } return null @@ -257,15 +257,15 @@ function ondisable_body(prop: ptr) -> Node { # Gated on `len(g_events) > 0`, so a program with no events is byte-identical. var g_events: []Node # each: an N_EVENT node (s = name, kids = payload fields, ival=1 if cancellable) var g_onlisten: []Node # each: N_BLOCK, s = event name, a = listener body block -var g_cancel_addr: ptr = null # EV3: address of the current cancellable dispatch's flag (null outside one) +var g_cancel_addr: pointer = null # EV3: address of the current cancellable dispatch's flag (null outside one) function register_event(n: Node) -> void { push(g_events, n) } -function find_event(name: ptr) -> Node { +function find_event(name: pointer) -> Node { var i = 0 while i < len(g_events) { if (g_events[i].s == name) { return g_events[i] }; i = i + 1 } return null } -function register_onlisten(evt: ptr, body: Node) -> void { +function register_onlisten(evt: pointer, body: Node) -> void { let n = node(N_BLOCK); n.s = evt; n.a = body; push(g_onlisten, n) } @@ -274,7 +274,7 @@ function register_onlisten(evt: ptr, body: Node) -> void { # presence in g_events is what makes each lifecycle fire site also `emit` it, so # `find_event(name) != null` doubles as the "is this hook public?" test. Names are # the stable ABI contract: `model__spawn`, `model__despawn`, etc. -function ensure_event(name: ptr, with_reason: bool) -> void { +function ensure_event(name: pointer, with_reason: bool) -> void { if (find_event(name) != null) { return } let n = node(N_EVENT); n.s = name let ent = node(N_FIELD); ent.s = "entity"; ent.ty = "int"; push(n.kids, ent) @@ -282,7 +282,7 @@ function ensure_event(name: ptr, with_reason: bool) -> void { register_event(n) } # a promoted scene/program event has no per-entity payload -function ensure_event_empty(name: ptr) -> void { +function ensure_event_empty(name: pointer) -> void { if (find_event(name) != null) { return } let n = node(N_EVENT); n.s = name; register_event(n) } @@ -291,33 +291,33 @@ function ensure_event_empty(name: ptr) -> void { # layer L` statement becomes "managed": it gets an @LE_ enabled flag and its # handlers gate on it. Only managed layers pay for this, so a scene program that # never toggles a layer is byte-identical. -var g_toggled_layers: []ptr -function note_toggled_layer(name: ptr) -> void { +var g_toggled_layers: []pointer +function note_toggled_layer(name: pointer) -> void { var i = 0 while i < len(g_toggled_layers) { if (g_toggled_layers[i] == name) { return }; i = i + 1 } push(g_toggled_layers, name) } -function is_toggled_layer(name: ptr) -> bool { +function is_toggled_layer(name: pointer) -> bool { var i = 0 while i < len(g_toggled_layers) { if (g_toggled_layers[i] == name) { return true }; i = i + 1 } return false } # is `name` a model (archetype)? — chooses model-vs-handler for a bare enable/disable -function is_model(name: ptr) -> bool { return find_arch_id(name) > 0 } +function is_model(name: pointer) -> bool { return find_arch_id(name) > 0 } # local variable environment function loc_reset() -> void { nloc = 0 } # push a local. Defaults to mutable (params, loop and query bindings are all # reassignable/rebindable); a `let` binding marks its slot immutable afterward # via loc_set_mut, so a later `name = …` can be rejected. -function loc_push(name: ptr, r: ptr, ty: ptr) -> void { +function loc_push(name: pointer, r: pointer, ty: pointer) -> void { if nloc < len(loc_name) { loc_name[nloc] = name; loc_reg[nloc] = r; loc_ty[nloc] = ty; loc_mut[nloc] = 1 } else { push(loc_name, name); push(loc_reg, r); push(loc_ty, ty); push(loc_mut, 1) } nloc = nloc + 1 } function loc_set_mut(m: int) -> void { if nloc > 0 { loc_mut[nloc - 1] = m } } -function loc_find(name: ptr) -> int { +function loc_find(name: pointer) -> int { var i = nloc - 1 while i >= 0 { if (loc_name[i] == name) { return i }; i = i - 1 } return 0 - 1 diff --git a/selfhost/emit_decl.ludic b/selfhost/emit_decl.ludic index 3d4263e1..676ca775 100644 --- a/selfhost/emit_decl.ludic +++ b/selfhost/emit_decl.ludic @@ -71,9 +71,9 @@ function emit_program() -> void { g_uses_intstr = false g_uses_strslice = false g_uses_loopback = false - loc_name = new []ptr; loc_reg = new []ptr; loc_ty = new []ptr; loc_mut = new []int - brk_lbl = new []ptr; cnt_lbl = new []ptr - self_stk = new []ptr + loc_name = new []pointer; loc_reg = new []pointer; loc_ty = new []pointer; loc_mut = new []int + brk_lbl = new []pointer; cnt_lbl = new []pointer + self_stk = new []pointer mach_stk = new []Node emit_header() emit_extern_decls() @@ -109,7 +109,7 @@ function emit_program() -> void { # Flush the emitted IR. With a null path it goes to stdout (the pipe the shell # drivers read); with a path it is written to that file so ludicc can hand it to # clang itself. -function ir_flush(path: ptr) -> bool { +function ir_flush(path: pointer) -> bool { let h = buf_str(head) let c = buf_str(code) if (path == null) { # raw IR to stdout (no trailing newline) diff --git a/selfhost/emit_ease.ludic b/selfhost/emit_ease.ludic index 93a7528a..82143b8f 100644 --- a/selfhost/emit_ease.ludic +++ b/selfhost/emit_ease.ludic @@ -2,19 +2,19 @@ # t in 0.0..1.0, returning an eased fixed. All pure Q16.16, deterministic. The # "juice" layer that makes motion feel good (Robert Penner's easings). -function is_ease_ns(meth: ptr) -> bool { +function is_ease_ns(meth: pointer) -> bool { if (meth == "in") or (meth == "out") or (meth == "in_out") { return true } if (meth == "back") or (meth == "bounce") or (meth == "elastic") { return true } return false } # n1 * u * u (u a fixed code) -> code of a fixed i32 -function ease_bounce_seg(u: ptr) -> ptr { +function ease_bounce_seg(u: pointer) -> pointer { let uu = fx_mul_code(u, u) return fx_mul_code(uu, "495616") # 7.5625 * u*u } -function emit_ease_ns(meth: ptr, e: Node) -> Val { +function emit_ease_ns(meth: pointer, e: Node) -> Val { let t = emit_expr(e.kids[0]) if (meth == "in") { # ease-in quad: t*t return val(fx_mul_code(t.code, t.code), "fixed") diff --git a/selfhost/emit_expr.ludic b/selfhost/emit_expr.ludic index e17815ed..d12ff898 100644 --- a/selfhost/emit_expr.ludic +++ b/selfhost/emit_expr.ludic @@ -1,6 +1,6 @@ # emit_expr.ludic — lower an expression to IR, returning its register and type. -function emit_load_at(addr: ptr, ty: ptr) -> Val { +function emit_load_at(addr: pointer, ty: pointer) -> Val { let r = emit_bind(`load {llty(ty)}, ptr {addr}`) return val(r, ty) } @@ -26,7 +26,7 @@ function emit_logic(e: Node) -> Val { return val(emit_bind(`load i32, ptr {slot}`), "bool") } -function cmp_code(op: ptr) -> ptr { +function cmp_code(op: pointer) -> pointer { if (op == ("<")) { return "slt" } if (op == ("<=")) { return "sle" } if (op == (">")) { return "sgt" } @@ -34,10 +34,10 @@ function cmp_code(op: ptr) -> ptr { if (op == ("==")) { return "eq" } return "ne" } -function is_cmp(op: ptr) -> bool { +function is_cmp(op: pointer) -> bool { return (op == ("<")) or (op == ("<=")) or (op == (">")) or (op == (">=")) or (op == ("==")) or (op == ("!=")) } -function arith_code(op: ptr) -> ptr { +function arith_code(op: pointer) -> pointer { if (op == ("+")) { return "add" } if (op == ("-")) { return "sub" } if (op == ("*")) { return "mul" } @@ -51,7 +51,7 @@ function arith_code(op: ptr) -> ptr { } # widen an int value to Q16.16 by shifting left 16 (a fixed value passes through) -function to_fixed(v: Val) -> ptr { +function to_fixed(v: Val) -> pointer { if (v.ty == "fixed") { return v.code } return emit_bind(`shl i32 {v.code}, 16`) } @@ -59,7 +59,7 @@ function to_fixed(v: Val) -> ptr { # coerce a value's code to the LLVM type of `target`, for the only cross-width # pair the language has: int (i32) <-> long (i64). int widens with sext, long # narrows with trunc; everything else (same width, or ptr) passes through. -function coerce_code(v: Val, target: ptr) -> ptr { +function coerce_code(v: Val, target: pointer) -> pointer { let lt = llty(target) let vt = llty(v.ty) if (lt == vt) { return v.code } @@ -69,14 +69,14 @@ function coerce_code(v: Val, target: ptr) -> ptr { } # widen an int value to i64 (a long passes through) — the long analogue of to_fixed -function to_long(v: Val) -> ptr { +function to_long(v: Val) -> pointer { if (llty(v.ty) == "i64") { return v.code } return emit_bind(`sext i32 {v.code} to i64`) } # string operators: `a + b` concatenates, `a == b` / `a != b` compare by content. # Both call the @fn_str_* prelude (emitted once per program that uses them). -function emit_str_op(op: ptr, a: Val, b: Val) -> Val { +function emit_str_op(op: pointer, a: Val, b: Val) -> Val { g_uses_str = true if (op == ("+")) { return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "string") @@ -152,7 +152,7 @@ function args_are_named(e: Node) -> bool { while i < len(e.kids) { if e.kids[i].kind == E_FINIT { return true }; i = i + 1 } return false } -function reorder_named(e: Node, labels: []ptr) -> void { +function reorder_named(e: Node, labels: []pointer) -> void { if not args_are_named(e) { return } var i = 0 while i < len(e.kids) { @@ -173,15 +173,15 @@ function reorder_named(e: Node, labels: []ptr) -> void { e.kids = out } # The parameter labels of a resolved fn/extern, in declaration order. -function param_labels(fn: Node) -> []ptr { - let out = new []ptr +function param_labels(fn: Node) -> []pointer { + let out = new []pointer var i = 0 while i < len(fn.kids) { if fn.kids[i].kind == N_PARAM { push(out, fn.kids[i].s) }; i = i + 1 } return out } -function param_types(fn: Node) -> []ptr { - let out = new []ptr +function param_types(fn: Node) -> []pointer { + let out = new []pointer var i = 0 while i < len(fn.kids) { if fn.kids[i].kind == N_PARAM { push(out, fn.kids[i].ty) }; i = i + 1 } return out @@ -192,7 +192,7 @@ function param_types(fn: Node) -> []ptr { # runtime builtin plus the parameter labels callers may use as named arguments; # after reordering we rewrite the callee to that bare name and fall back into the # ordinary builtin path (which resolves it to its rt_ function). -function emit_ns_call(ns: ptr, meth: ptr, e: Node) -> Val { +function emit_ns_call(ns: pointer, meth: pointer, e: Node) -> Val { # Math.* is computed inline (deterministic fixed-point), not routed through a # bare rt_ name — so `floor`/`round`/`lerp` never leak into the bare namespace. if (ns == "Math") { @@ -231,8 +231,8 @@ function emit_ns_call(ns: ptr, meth: ptr, e: Node) -> Val { if is_hash_ns(meth) { return emit_hash_ns(meth, e) } perr(`unknown builtin Hash.{meth}`) } - var bare: ptr = null - let labels = new []ptr + var bare: pointer = null + let labels = new []pointer if (ns == "Screen") { if (meth == "clear") { bare = "clear"; push(labels, "color") } if (meth == "fill_rectangle") { bare = "fill_rect"; push(labels, "x"); push(labels, "y"); push(labels, "width"); push(labels, "height"); push(labels, "color") } @@ -428,7 +428,7 @@ function emit_call(e: Node) -> Val { if (name == "bytes") { # bytes(n): allocate n bytes -> a byte buffer let n = emit_expr(e.kids[0]) let w = emit_bind(`zext i32 {n.code} to i64`) - return val(emit_bind(`call ptr @malloc(i64 {w})`), "ptr") + return val(emit_bind(`call ptr @malloc(i64 {w})`), "pointer") } if (name == "words") { # words(n): allocate n 32-bit words let n = emit_expr(e.kids[0]) @@ -470,8 +470,8 @@ function emit_call(e: Node) -> Val { let ext = find_extern(name) if (ext != null) { reorder_named(e, param_labels(ext)) - let eargs = new []ptr - let eatys = new []ptr + let eargs = new []pointer + let eatys = new []pointer var ei = 0 while ei < len(e.kids) { let v = emit_expr(e.kids[ei]); push(eargs, v.code); push(eatys, v.ty); ei = ei + 1 } let erl = llty(ext.ty) @@ -501,8 +501,8 @@ function emit_call(e: Node) -> Val { # evaluate args first (their IR is emitted before the call instruction), coercing # each to the parameter's declared type so an int passed for a `long` widens. let ptys = param_types(fn2) - let args = new []ptr - let atys = new []ptr + let args = new []pointer + let atys = new []pointer var i = 0 while i < len(e.kids) { let v = emit_expr(e.kids[i]) @@ -530,7 +530,7 @@ function emit_expr(e: Node) -> Val { if e.kind == E_INT { return val(itoa(e.ival), "int") } if e.kind == E_FLOAT { return val(itoa(e.ival), "fixed") } if e.kind == E_BOOL { return val(itoa(e.ival), "bool") } - if e.kind == E_NULL { return val("null", "ptr") } + if e.kind == E_NULL { return val("null", "pointer") } if e.kind == E_SLICE { # s[a..b] -> a fresh substring let base = emit_expr(e.a) let lo = emit_expr(e.b) diff --git a/selfhost/emit_game.ludic b/selfhost/emit_game.ludic index b9255fbd..ffce40ed 100644 --- a/selfhost/emit_game.ludic +++ b/selfhost/emit_game.ludic @@ -50,7 +50,7 @@ function emit_call_one(d: Node) -> void { # declaration (draw) order. The active scene is snapshotted once per phase, so a # `become` mid-phase takes effect at the next phase boundary — exactly one scene # is active within any single phase. -function emit_calls_for_phase(phase: ptr) -> void { +function emit_calls_for_phase(phase: pointer) -> void { var i = 0 while i < len(prog) { let d = prog[i] @@ -81,7 +81,7 @@ function emit_calls_for_phase(phase: ptr) -> void { # on enter / on exit compile to void functions @scene_enter_ / # @scene_exit_, called at the transition point (and enter at boot for the # start scene). Emitted for every scene, empty body when the hook is absent. -function emit_scene_fn(name: ptr, kind: ptr, body: Node) -> void { +function emit_scene_fn(name: pointer, kind: pointer, body: Node) -> void { ll_t = 0; ll_lbl = 0; g_term = false; loc_reset(); nloop = 0; nself = 0 ret_ty = "void" let fbody = buf_new() diff --git a/selfhost/emit_hash.ludic b/selfhost/emit_hash.ludic index 7171940e..765e5632 100644 --- a/selfhost/emit_hash.ludic +++ b/selfhost/emit_hash.ludic @@ -11,7 +11,7 @@ # Hash.mix(x) fmix32 avalanche of a single int (turn a counter into a seed) # Hash.combine(...) fold several ints into one (e.g. world_seed, cx, cy) -function is_hash_ns(meth: ptr) -> bool { +function is_hash_ns(meth: pointer) -> bool { if (meth == "of") or (meth == "fnv1a") or (meth == "crc32") { return true } if (meth == "mix") or (meth == "combine") { return true } if (meth == "of64") or (meth == "fnv1a_64") or (meth == "mix64") { return true } @@ -21,7 +21,7 @@ function is_hash_ns(meth: ptr) -> bool { # fmix32 (MurmurHash3 finalizer) of a single i32 -> code of an i32. A strong # avalanche: flips ~half the output bits for any one input bit. Used on its own # (Hash.mix) and nowhere else — combine has its own mixing step. -function hash_mix_code(x: ptr) -> ptr { +function hash_mix_code(x: pointer) -> pointer { let a = emit_bind(`lshr i32 {x}, 16`) let b = emit_bind(`xor i32 {x}, {a}`) let c = emit_bind(`mul i32 {b}, -2048144789`) # * 0x85ebca6b @@ -35,7 +35,7 @@ function hash_mix_code(x: ptr) -> ptr { # fmix64 (MurmurHash3 64-bit finalizer) of a single i64 -> code of an i64. The # 64-bit twin of hash_mix_code: shift by 33 and multiply by the two 64-bit # constants. Backs Hash.mix64. -function hash_mix64_code(x: ptr) -> ptr { +function hash_mix64_code(x: pointer) -> pointer { let a = emit_bind(`lshr i64 {x}, 33`) let b = emit_bind(`xor i64 {x}, {a}`) let c = emit_bind(`mul i64 {b}, -49064778989728563`) # * 0xff51afd7ed558ccd @@ -46,7 +46,7 @@ function hash_mix64_code(x: ptr) -> ptr { return emit_bind(`xor i64 {f}, {g}`) } -function emit_hash_ns(meth: ptr, e: Node) -> Val { +function emit_hash_ns(meth: pointer, e: Node) -> Val { if (meth == "of") or (meth == "fnv1a") { # FNV-1a 32-bit over the bytes g_uses_hashrt = true let s = emit_expr(e.kids[0]) @@ -74,7 +74,7 @@ function emit_hash_ns(meth: ptr, e: Node) -> Val { # seed = seed ^ (v + 0x9e3779b9 + (seed << 6) + (seed >> 2)) # order-sensitive and deterministic; seed starts at 0 so a single argument is # still well-mixed with the golden-ratio constant. - var seed: ptr = "0" + var seed: pointer = "0" var i = 0 while i < len(e.kids) { let v = emit_expr(e.kids[i]) diff --git a/selfhost/emit_head.ludic b/selfhost/emit_head.ludic index fdc9d787..e6fe4099 100644 --- a/selfhost/emit_head.ludic +++ b/selfhost/emit_head.ludic @@ -4,7 +4,7 @@ function hexdig(n: int) -> int { if n < 10 { return 48 + n }; return 55 + n } # 0-9 A-F # emit `@.strN = ... c"escaped\00"` and return its name; % and non-print -> \XX -function emit_str_const(s: ptr) -> ptr { +function emit_str_const(s: pointer) -> pointer { let name = `@.str{itoa(ll_str)}` ll_str = ll_str + 1 let n = len(s) @@ -25,7 +25,7 @@ function emit_str_const(s: ptr) -> ptr { } # the constant initializer for a global var: a literal, or 0/null -function global_init(d: Node) -> ptr { +function global_init(d: Node) -> pointer { if (d.a == null) { if (llty(d.ty) == "ptr") { return "null" }; return "0" } let e = d.a if e.kind == E_INT or e.kind == E_FLOAT or e.kind == E_BOOL { return itoa(e.ival) } diff --git a/selfhost/emit_intrin.ludic b/selfhost/emit_intrin.ludic index d50d845e..231dafb3 100644 --- a/selfhost/emit_intrin.ludic +++ b/selfhost/emit_intrin.ludic @@ -6,7 +6,7 @@ var g_intrin_ok: bool = false # is `name` a low-level intrinsic? A pure name check, so it can gate dispatch # without evaluating arguments (which could clobber shared state). -function is_intrinsic(name: ptr) -> bool { +function is_intrinsic(name: pointer) -> bool { if (name == "resize") { return true } if (name == "file_open") or (name == "file_read") or (name == "file_write") { return true } if (name == "file_seek") or (name == "file_tell") or (name == "file_close") { return true } @@ -16,22 +16,22 @@ function is_intrinsic(name: ptr) -> bool { return false } # emit " = \n" and return r -function emit_bind(rest: ptr) -> ptr { let r = nreg(); emit(" "); emit(r); emit(" = "); emit(rest); emit("\n"); return r } +function emit_bind(rest: pointer) -> pointer { let r = nreg(); emit(" "); emit(r); emit(" = "); emit(rest); emit("\n"); return r } -function arg_code(e: Node, i: int) -> ptr { let v = emit_expr(e.kids[i]); return v.code } +function arg_code(e: Node, i: int) -> pointer { let v = emit_expr(e.kids[i]); return v.code } -function emit_intrinsic(name: ptr, e: Node) -> Val { +function emit_intrinsic(name: pointer, e: Node) -> Val { g_intrin_ok = true # ptr_null / ptr_is_null are the `null` literal and `x == null` now. # mem_alloc is bytes(n) / words(n) now (see emit_call). if (name == "resize") { let p = arg_code(e, 0); let n = arg_code(e, 1) let w = emit_bind(`zext i32 {n} to i64`) - return val(emit_bind(`call ptr @realloc(ptr {p}, i64 {w})`), "ptr") + return val(emit_bind(`call ptr @realloc(ptr {p}, i64 {w})`), "pointer") } if (name == "file_open") { let p = arg_code(e, 0); let m = arg_code(e, 1) - return val(emit_bind(`call ptr @fopen(ptr {p}, ptr {m})`), "ptr") + return val(emit_bind(`call ptr @fopen(ptr {p}, ptr {m})`), "pointer") } if (name == "file_read") or (name == "file_write") { let f = arg_code(e, 0); let b = arg_code(e, 1); let n = arg_code(e, 2) @@ -71,8 +71,8 @@ function emit_intrinsic(name: ptr, e: Node) -> Val { g_term = true return val("0", "void") } - if (name == "file_stderr") { return val(emit_bind("load ptr, ptr @__stderrp"), "ptr") } - if (name == "file_stdout") { return val(emit_bind("load ptr, ptr @__stdoutp"), "ptr") } + if (name == "file_stderr") { return val(emit_bind("load ptr, ptr @__stderrp"), "pointer") } + if (name == "file_stdout") { return val(emit_bind("load ptr, ptr @__stdoutp"), "pointer") } if (name == "run") { let c = arg_code(e, 0) return val(emit_bind(`call i32 @system(ptr {c})`), "int") diff --git a/selfhost/emit_intrin2.ludic b/selfhost/emit_intrin2.ludic index 1151f6d6..9758642c 100644 --- a/selfhost/emit_intrin2.ludic +++ b/selfhost/emit_intrin2.ludic @@ -4,7 +4,7 @@ var g_windowed: bool = false # headless by default (games read stdin / dump PPM) -function is_intrinsic2(name: ptr) -> bool { +function is_intrinsic2(name: pointer) -> bool { if (name == "free") or (name == "fill") { return true } if (name == "offset") or (name == "read_char") { return true } if (name == "as_fixed") or (name == "as_int") { return true } @@ -14,7 +14,7 @@ function is_intrinsic2(name: ptr) -> bool { return false } -function emit_intrinsic2(name: ptr, e: Node) -> Val { +function emit_intrinsic2(name: pointer, e: Node) -> Val { if (name == "free") { let p = arg_code(e, 0); emit(" call void @free(ptr "); emit(p); emit(")\n"); return val("0", "void") } @@ -28,7 +28,7 @@ function emit_intrinsic2(name: ptr, e: Node) -> Val { let p = arg_code(e, 0); let n = arg_code(e, 1) let g = nreg() emit(" "); emit(g); emit(" = getelementptr inbounds i8, ptr "); emit(p); emit(", i32 "); emit(n); emit("\n") - return val(g, "ptr") + return val(g, "pointer") } if (name == "read_char") { return val(emit_bind("call i32 @getchar()"), "int") } if (name == "as_fixed") { let a = emit_expr(e.kids[0]); return val(a.code, "fixed") } diff --git a/selfhost/emit_list.ludic b/selfhost/emit_list.ludic index c21255f5..74eada09 100644 --- a/selfhost/emit_list.ludic +++ b/selfhost/emit_list.ludic @@ -5,13 +5,13 @@ # for reference elements (structs/strings), matching how `==` behaves elsewhere. # address of element `idx` (an i32 code) in slice header `h`, element LLVM type `elt` -function list_elem_addr(h: ptr, elt: ptr, idx: ptr) -> ptr { +function list_elem_addr(h: pointer, elt: pointer, idx: pointer) -> pointer { let dp = slice_field(h, 0) let data = emit_bind(`load ptr, ptr {dp}`) return emit_bind(`getelementptr inbounds {elt}, ptr {data}, i32 {idx}`) } -function is_list_ns(meth: ptr) -> bool { +function is_list_ns(meth: pointer) -> bool { if (meth == "len") or (meth == "push") or (meth == "clear") { return true } if (meth == "first") or (meth == "last") or (meth == "pop") or (meth == "swap") { return true } if (meth == "contains") or (meth == "index_of") or (meth == "reverse") { return true } @@ -21,7 +21,7 @@ function is_list_ns(meth: ptr) -> bool { # grow the slice's backing buffer if it is full, exactly as push does (double, # or 8 from empty). Leaves length untouched; only capacity/data may change. -function list_grow_if_full(h: ptr, elt: ptr) -> void { +function list_grow_if_full(h: pointer, elt: pointer) -> void { let lp = slice_field(h, 1); let cp = slice_field(h, 2); let dp = slice_field(h, 0) let l = emit_bind(`load i32, ptr {lp}`) let c = emit_bind(`load i32, ptr {cp}`) @@ -43,7 +43,7 @@ function list_grow_if_full(h: ptr, elt: ptr) -> void { emit(done); emit(":\n") } -function emit_list_ns(meth: ptr, e: Node) -> Val { +function emit_list_ns(meth: pointer, e: Node) -> Val { if (meth == "len") { return emit_len(e) } # same header length as len(s) if (meth == "push") { return emit_push(e) } # same as push(s, v) let s = emit_expr(e.kids[0]) diff --git a/selfhost/emit_math.ludic b/selfhost/emit_math.ludic index f9255790..221924e2 100644 --- a/selfhost/emit_math.ludic +++ b/selfhost/emit_math.ludic @@ -5,11 +5,11 @@ # integer root, @fn_fx_sin a 256-entry interpolated sine table). Everything is # plain integer IR, so it is bit-identical on every platform. -function is_math_builtin(name: ptr) -> bool { +function is_math_builtin(name: pointer) -> bool { return (name == "min") or (name == "max") or (name == "abs") or (name == "clamp") } -function emit_math_builtin(name: ptr, e: Node) -> Val { +function emit_math_builtin(name: pointer, e: Node) -> Val { if (name == "abs") { let a = emit_expr(e.kids[0]) let c = emit_bind(`icmp slt i32 {a.code}, 0`) @@ -32,7 +32,7 @@ function emit_math_builtin(name: ptr, e: Node) -> Val { } # a * b in Q16.16 (64-bit intermediate, arithmetic shift back) -> code of an i32 -function fx_mul_code(a: ptr, b: ptr) -> ptr { +function fx_mul_code(a: pointer, b: pointer) -> pointer { let a64 = emit_bind(`sext i32 {a} to i64`) let b64 = emit_bind(`sext i32 {b} to i64`) let m = emit_bind(`mul i64 {a64}, {b64}`) @@ -41,7 +41,7 @@ function fx_mul_code(a: ptr, b: ptr) -> ptr { } # a / b in Q16.16 (shift the numerator up before the divide) -> code of an i32 -function fx_div_code(a: ptr, b: ptr) -> ptr { +function fx_div_code(a: pointer, b: pointer) -> pointer { let a64 = emit_bind(`sext i32 {a} to i64`) let ash = emit_bind(`shl i64 {a64}, 16`) let b64 = emit_bind(`sext i32 {b} to i64`) @@ -50,14 +50,14 @@ function fx_div_code(a: ptr, b: ptr) -> ptr { } # lerp(a, b, t) = a + (b - a) * t, all Q16.16 -> code of a fixed i32 -function fx_lerp_code(a: ptr, b: ptr, t: ptr) -> ptr { +function fx_lerp_code(a: pointer, b: pointer, t: pointer) -> pointer { let d = emit_bind(`sub i32 {b}, {a}`) let dt = fx_mul_code(d, t) return emit_bind(`add i32 {a}, {dt}`) } # inverse_lerp(a, b, v) = (v - a) / (b - a), all Q16.16 -> code of a fixed i32 -function fx_inv_lerp_code(a: ptr, b: ptr, v: ptr) -> ptr { +function fx_inv_lerp_code(a: pointer, b: pointer, v: pointer) -> pointer { let num = emit_bind(`sub i32 {v}, {a}`) let den = emit_bind(`sub i32 {b}, {a}`) return fx_div_code(num, den) @@ -66,7 +66,7 @@ function fx_inv_lerp_code(a: ptr, b: ptr, v: ptr) -> ptr { # Math.* — the namespaced surface. min/max/abs/clamp reuse the bare lowering; # the rest are new deterministic fixed-point helpers. Returns g_intrin-style via # a direct Val; callers guard with is_math_ns first. -function is_math_ns(meth: ptr) -> bool { +function is_math_ns(meth: pointer) -> bool { if (meth == "min") or (meth == "max") or (meth == "abs") or (meth == "clamp") { return true } if (meth == "sign") or (meth == "floor") or (meth == "ceil") or (meth == "round") { return true } if (meth == "lerp") or (meth == "inverse_lerp") or (meth == "remap") { return true } @@ -79,7 +79,7 @@ function is_math_ns(meth: ptr) -> bool { return false } -function emit_math_ns(meth: ptr, e: Node) -> Val { +function emit_math_ns(meth: pointer, e: Node) -> Val { if (meth == "min") or (meth == "max") or (meth == "abs") or (meth == "clamp") { return emit_math_builtin(meth, e) } diff --git a/selfhost/emit_mem.ludic b/selfhost/emit_mem.ludic index 2f179bd4..64b89ce2 100644 --- a/selfhost/emit_mem.ludic +++ b/selfhost/emit_mem.ludic @@ -3,17 +3,17 @@ # read and write one byte. The low-level escape hatch, PICO-8's memcpy/memset/ # peek/poke by another name. -function is_mem_ns(meth: ptr) -> bool { +function is_mem_ns(meth: pointer) -> bool { if (meth == "bytes") or (meth == "words") { return true } if (meth == "copy") or (meth == "fill") or (meth == "peek") or (meth == "poke") { return true } return false } -function emit_mem_ns(meth: ptr, e: Node) -> Val { +function emit_mem_ns(meth: pointer, e: Node) -> Val { if (meth == "bytes") { # allocate n bytes -> a byte buffer let n = emit_expr(e.kids[0]) let w = emit_bind(`zext i32 {n.code} to i64`) - return val(emit_bind(`call ptr @malloc(i64 {w})`), "ptr") + return val(emit_bind(`call ptr @malloc(i64 {w})`), "pointer") } if (meth == "words") { # allocate n 32-bit words let n = emit_expr(e.kids[0]) diff --git a/selfhost/emit_net.ludic b/selfhost/emit_net.ludic index ca769ce7..b965016c 100644 --- a/selfhost/emit_net.ludic +++ b/selfhost/emit_net.ludic @@ -19,8 +19,8 @@ var g_uses_loopback: bool = false # component participates in the entity's model (the model member is @Sync, # member.ival==1). Participation is decided per model use-site. -function net_field_ibytes(ty: ptr) -> int { if (llty(ty) == "i8") { return 1 }; return 4 } -function net_field_bytes(ty: ptr) -> ptr { if (llty(ty) == "i8") { return "1" }; return "4" } +function net_field_ibytes(ty: pointer) -> int { if (llty(ty) == "i8") { return 1 }; return 4 } +function net_field_bytes(ty: pointer) -> pointer { if (llty(ty) == "i8") { return "1" }; return "4" } # total replicated bytes for model m (compile-time constant) function net_model_bytes(m: Node) -> int { @@ -67,7 +67,7 @@ function net_has_role() -> bool { function net_any() -> bool { return net_has_sync() or net_has_owned() or net_has_role() } # ---- diagnostics ------------------------------------------------------------- -function net_warn(msg: ptr) -> void { +function net_warn(msg: pointer) -> void { let e = file_stderr() file_write(e, "ludicc(self): warning: ", 23) file_write(e, msg, len(msg)) @@ -300,14 +300,14 @@ function net_has_remote() -> bool { return false } # stable wire id for an event = its index in g_events (same program both peers) -function net_event_id(name: ptr) -> int { +function net_event_id(name: pointer) -> int { var i = 0 while i < len(g_events) { if (g_events[i].s == name) { return i }; i = i + 1 } return 0 - 1 } # the transport symbols: an `extern fn` override, else the built-in loopback. -function net_send_sym() -> ptr { let x = find_extern("net_send"); if (x != null) { return x.a.s }; return "L_net_send" } -function net_poll_sym() -> ptr { let x = find_extern("net_poll"); if (x != null) { return x.a.s }; return "L_net_poll" } +function net_send_sym() -> pointer { let x = find_extern("net_send"); if (x != null) { return x.a.s }; return "L_net_send" } +function net_poll_sym() -> pointer { let x = find_extern("net_poll"); if (x != null) { return x.a.s }; return "L_net_poll" } # net_pump(): poll every pending frame and re-emit it locally. The receive path # of a remote event — the runtime/game calls this each tick. diff --git a/selfhost/emit_new.ludic b/selfhost/emit_new.ludic index 16629fad..8d15c052 100644 --- a/selfhost/emit_new.ludic +++ b/selfhost/emit_new.ludic @@ -2,12 +2,12 @@ # push(slice, v) and len(slice). Slices are a { data, len, cap } header the # holder points at, so growth is visible to every holder. -function emit_sizeof(llt: ptr) -> ptr { +function emit_sizeof(llt: pointer) -> pointer { let p = emit_bind(`getelementptr {llt}, ptr null, i32 1`) return emit_bind(`ptrtoint ptr {p} to i64`) } -function emit_new_struct(name: ptr) -> Val { +function emit_new_struct(name: pointer) -> Val { let s = layout_node(name) # a struct or a property — same shape if (s == null) { perr("unknown record type in new") } let lty = layout_ty(name) @@ -29,7 +29,7 @@ function emit_new_struct(name: ptr) -> Val { return val(obj, name) } -function emit_new_slice(ty: ptr) -> Val { +function emit_new_slice(ty: pointer) -> Val { let sz = emit_sizeof("%LSlice") let h = emit_bind(`call ptr @malloc(i64 {sz})`) let d0 = nreg(); emit(" "); emit(d0); emit(" = getelementptr inbounds %LSlice, ptr "); emit(h); emit(", i32 0, i32 0\n") @@ -41,7 +41,7 @@ function emit_new_slice(ty: ptr) -> Val { return val(h, ty) } -function slice_field(h: ptr, i: int) -> ptr { +function slice_field(h: pointer, i: int) -> pointer { let r = nreg() emit(" "); emit(r); emit(" = getelementptr inbounds %LSlice, ptr "); emit(h) emit(", i32 0, i32 "); emit(itoa(i)); emit("\n") diff --git a/selfhost/emit_query.ludic b/selfhost/emit_query.ludic index 1579c309..49713735 100644 --- a/selfhost/emit_query.ludic +++ b/selfhost/emit_query.ludic @@ -2,7 +2,7 @@ # components/archetypes each carries, binds the requested components, and runs # the body once per match. Mirrors ll_query in compiler/back/ir_ecs.c. -function find_arch_id(name: ptr) -> int { +function find_arch_id(name: pointer) -> int { var i = 0; var n = 1 while i < len(prog) { if prog[i].kind == N_ARCH { if (prog[i].s == name) { return n }; n = n + 1 }; i = i + 1 } return 0 diff --git a/selfhost/emit_save.ludic b/selfhost/emit_save.ludic index 613bcd2d..9252c597 100644 --- a/selfhost/emit_save.ludic +++ b/selfhost/emit_save.ludic @@ -13,10 +13,10 @@ var g_iok: int = 0 # NOTE: a string initializer on a module `ptr` var lowers to null (global_init), # so these are seeded at runtime in emit_snapshot before first use — never read # them uninitialized (a null string `==` would deref and crash the compiler). -var g_snap_mode: ptr = null # "file" | "save" | "load" | "size" -var g_off: ptr = null # current byte-offset register, buffer modes +var g_snap_mode: pointer = null # "file" | "save" | "load" | "size" +var g_off: pointer = null # current byte-offset register, buffer modes -function emit_io(fn2: ptr, p: ptr, bytes: ptr) -> void { +function emit_io(fn2: pointer, p: pointer, bytes: pointer) -> void { if (g_snap_mode == "file") { let r = `%io{itoa(g_iok)}`; g_iok = g_iok + 1 emit(" "); emit(r); emit(" = call i64 @"); emit(fn2); emit("(ptr "); emit(p); emit(", i64 1, i64 "); emit(bytes); emit(", ptr %f)\n") @@ -43,7 +43,7 @@ function emit_io(fn2: ptr, p: ptr, bytes: ptr) -> void { g_iok = g_iok + 1 } -function emit_snapshot_blocks(fn2: ptr) -> void { +function emit_snapshot_blocks(fn2: pointer) -> void { g_iok = 0 g_off = "0" let me = itoa(MAX_ENT) diff --git a/selfhost/emit_spawn.ludic b/selfhost/emit_spawn.ludic index ddd4e57f..fa202b94 100644 --- a/selfhost/emit_spawn.ludic +++ b/selfhost/emit_spawn.ludic @@ -1,7 +1,7 @@ # emit_spawn.ludic — spawn / despawn / self(), and seeding a component's fields # from its declared defaults plus any per-spawn overrides. -function emit_init_component(e: ptr, comp: ptr, rec: Node) -> void { +function emit_init_component(e: pointer, comp: pointer, rec: Node) -> void { let me = itoa(MAX_ENT) let c = find_comp(comp) if (c == null) { perr(`spawn: unknown property {comp}`) } @@ -54,7 +54,7 @@ function emit_init_component(e: ptr, comp: ptr, rec: Node) -> void { # bind each of a model's properties to entity `e`'s component storage, so an # @OnSpawn hook body can address them by name (like a query binding for one entity). -function emit_bind_props(model: Node, e: ptr) -> void { +function emit_bind_props(model: Node, e: pointer) -> void { let me = itoa(MAX_ENT) var c = 0 while c < len(model.kids) { @@ -68,7 +68,7 @@ function emit_bind_props(model: Node, e: ptr) -> void { } } -function emit_spawn(st: Node) -> ptr { +function emit_spawn(st: Node) -> pointer { let e = emit_bind("call i32 @L_alloc()") let ak = find_arch_id(st.s) if ak > 0 { diff --git a/selfhost/emit_stmt.ludic b/selfhost/emit_stmt.ludic index de92c5a7..d95eb703 100644 --- a/selfhost/emit_stmt.ludic +++ b/selfhost/emit_stmt.ludic @@ -11,7 +11,7 @@ function emit_block(b: Node) -> void { } # store `val` (llvm type `lt`) into address `addr` -function store_at(lt: ptr, v: ptr, addr: ptr) -> void { +function store_at(lt: pointer, v: pointer, addr: pointer) -> void { emit(" store "); emit(lt); emit(" "); emit(v); emit(", ptr "); emit(addr); emit("\n") } @@ -167,8 +167,8 @@ function emit_emit(st: Node) -> Val { let ev = find_event(st.s) if (ev == null) { perr(`emit: unknown event {st.s}`) } # evaluate each payload field in declared order (default for a missing arg) - let fcodes = new []ptr - let ftys = new []ptr + let fcodes = new []pointer + let ftys = new []pointer var f = 0 while f < len(ev.kids) { let fd = ev.kids[f] @@ -261,7 +261,7 @@ function emit_stmt(st: Node) -> void { perr("cannot emit statement") } -function loop_push(cont: ptr, brk: ptr) -> void { +function loop_push(cont: pointer, brk: pointer) -> void { if nloop < len(cnt_lbl) { cnt_lbl[nloop] = cont; brk_lbl[nloop] = brk } else { push(cnt_lbl, cont); push(brk_lbl, brk) } nloop = nloop + 1 diff --git a/selfhost/emit_text.ludic b/selfhost/emit_text.ludic index 0bf8f707..eb17500f 100644 --- a/selfhost/emit_text.ludic +++ b/selfhost/emit_text.ludic @@ -3,7 +3,7 @@ # contains/index_of/to_int) allocate nothing; slice/from_int/equals/concat reuse # the string preludes that the `+`, `s[a..b]` and string(int) operators emit. -function is_text_ns(meth: ptr) -> bool { +function is_text_ns(meth: pointer) -> bool { if (meth == "length") or (meth == "char_at") or (meth == "slice") { return true } if (meth == "equals") or (meth == "concat") or (meth == "to_int") or (meth == "from_int") { return true } if (meth == "starts_with") or (meth == "ends_with") { return true } @@ -14,7 +14,7 @@ function is_text_ns(meth: ptr) -> bool { return false } -function emit_text_ns(meth: ptr, e: Node) -> Val { +function emit_text_ns(meth: pointer, e: Node) -> Val { if (meth == "from_int") { # int -> string, same as string(n) let n = emit_expr(e.kids[0]) g_uses_intstr = true diff --git a/selfhost/emit_time.ludic b/selfhost/emit_time.ludic index 19fa1af3..4046a4ac 100644 --- a/selfhost/emit_time.ludic +++ b/selfhost/emit_time.ludic @@ -3,12 +3,12 @@ # the wall clock and is explicitly non-deterministic. The frame clock ticks at a # fixed 60 per second, so delta is the constant 1/60 s = 1092 in Q16.16. -function is_time_ns(meth: ptr) -> bool { +function is_time_ns(meth: pointer) -> bool { if (meth == "frame") or (meth == "delta") or (meth == "elapsed") or (meth == "now") { return true } return false } -function emit_time_ns(meth: ptr, e: Node) -> Val { +function emit_time_ns(meth: pointer, e: Node) -> Val { if (meth == "frame") { # completed frames since start return val(emit_bind("load i32, ptr @L_frame"), "int") } diff --git a/selfhost/emit_ui.ludic b/selfhost/emit_ui.ludic index 553b5b23..1fb5c3c0 100644 --- a/selfhost/emit_ui.ludic +++ b/selfhost/emit_ui.ludic @@ -14,7 +14,7 @@ function ui_wtype(w: Node) -> int { if (s == "image") { return 5 }; if (s == "spacer") { return 6 } return 0 } -function ui_prop(w: Node, key: ptr) -> Node { +function ui_prop(w: Node, key: pointer) -> Node { var i = 0 while i < len(w.b.kids) { if (w.b.kids[i].s == key) { return w.b.kids[i].a }; i = i + 1 } return null @@ -40,7 +40,7 @@ function has_ui() -> bool { } # index of a UI_: a ui block's root, or a widget's id= -function ui_index_of(nm: ptr) -> int { +function ui_index_of(nm: pointer) -> int { let s = nm[3..len(nm)] # strip "UI_" let u = 0; var bi = 0 var i = 0 @@ -56,14 +56,14 @@ function ui_index_of(nm: ptr) -> int { } return 0 } -function is_ui_ident(nm: ptr) -> bool { +function is_ui_ident(nm: pointer) -> bool { return len(nm) > 3 and nm[0] == 85 and nm[1] == 73 and nm[2] == 95 # "UI_" } -function ll_ui_set(idx: int, key: int, val: ptr) -> void { +function ll_ui_set(idx: int, key: int, val: pointer) -> void { emit(" call void @fn_rt_ui_set(i32 "); emit(itoa(idx)); emit(", i32 "); emit(itoa(key)); emit(", i32 "); emit(val); emit(")\n") } -function ui_prop_key(k: ptr) -> int { +function ui_prop_key(k: pointer) -> int { if (k == "w") { return 2 }; if (k == "h") { return 3 }; if (k == "x") { return 4 }; if (k == "y") { return 5 } if (k == "pad") { return 7 }; if (k == "gap") { return 8 }; if (k == "bg") { return 9 }; if (k == "fg") { return 10 } if (k == "border") { return 11 }; if (k == "grow") { return 13 }; if (k == "font") { return 14 }; if (k == "size") { return 15 } diff --git a/selfhost/io.ludic b/selfhost/io.ludic index 129756f3..aba29e1c 100644 --- a/selfhost/io.ludic +++ b/selfhost/io.ludic @@ -1,7 +1,7 @@ # io.ludic — reading the input file and writing the output, plus tiny stdio. # The compiler reads one .ludic file whole and emits LLVM IR text to stdout. -function read_file(path: string) -> ptr { +function read_file(path: string) -> pointer { let f = file_open(path, "rb") if (f == null) { return null } file_seek(f, 0, 2) @@ -15,7 +15,7 @@ function read_file(path: string) -> ptr { } # length of a NUL-terminated buffer -function cstr_len(s: ptr) -> int { +function cstr_len(s: pointer) -> int { var n = 0 while s[n] != 0 { n = n + 1 } return n diff --git a/selfhost/lex.ludic b/selfhost/lex.ludic index 452cb33d..1c3a09bb 100644 --- a/selfhost/lex.ludic +++ b/selfhost/lex.ludic @@ -11,18 +11,18 @@ const TK_EOF: int = 5 const TK_FLOAT: int = 6 const TK_INTERP: int = 7 # `text {expr} text` — raw content, split by the parser -property Tok { kind: int = 0, text: ptr = null, ival: int = 0, line: int = 0 } +property Tok { kind: int = 0, text: pointer = null, ival: int = 0, line: int = 0 } var toks: []Tok -function tok_push(kind: int, text: ptr, ival: int, line: int) -> void { +function tok_push(kind: int, text: pointer, ival: int, line: int) -> void { let t = new Tok t.kind = kind; t.text = text; t.ival = ival; t.line = line push(toks, t) } # does src match the 2-char operator op at position i? -function two_at(src: ptr, i: int, a: int, b: int) -> bool { +function two_at(src: pointer, i: int, a: int, b: int) -> bool { return src[i] == a and src[i + 1] == b } @@ -37,7 +37,7 @@ function is_op1(c: int) -> bool { return false } -function lex(src: ptr) -> void { +function lex(src: pointer) -> void { toks = new []Tok var i = 0 var line = 1 diff --git a/selfhost/ludicc.seed.ll b/selfhost/ludicc.seed.ll index 6eecf9b0..b7af9a4f 100644 --- a/selfhost/ludicc.seed.ll +++ b/selfhost/ludicc.seed.ll @@ -438,7 +438,7 @@ declare void @win_close() @.str337 = private unnamed_addr constant [3 x i8] c"i8\00" @.str338 = private unnamed_addr constant [6 x i8] c"words\00" @.str339 = private unnamed_addr constant [7 x i8] c"fixeds\00" -@.str340 = private unnamed_addr constant [5 x i8] c"ptrs\00" +@.str340 = private unnamed_addr constant [9 x i8] c"pointers\00" @.str341 = private unnamed_addr constant [4 x i8] c"ptr\00" @.str342 = private unnamed_addr constant [5 x i8] c"void\00" @.str343 = private unnamed_addr constant [5 x i8] c"void\00" @@ -611,7 +611,7 @@ declare void @win_close() @.str510 = private unnamed_addr constant [33 x i8] c"getelementptr inbounds i32, ptr \00" @.str511 = private unnamed_addr constant [7 x i8] c", i32 \00" @.str512 = private unnamed_addr constant [6 x i8] c"fixed\00" -@.str513 = private unnamed_addr constant [5 x i8] c"ptrs\00" +@.str513 = private unnamed_addr constant [9 x i8] c"pointers\00" @.str514 = private unnamed_addr constant [33 x i8] c"getelementptr inbounds ptr, ptr \00" @.str515 = private unnamed_addr constant [7 x i8] c", i32 \00" @.str516 = private unnamed_addr constant [4 x i8] c"ptr\00" @@ -652,12 +652,12 @@ declare void @win_close() @.str551 = private unnamed_addr constant [23 x i8] c"call ptr @realloc(ptr \00" @.str552 = private unnamed_addr constant [7 x i8] c", i64 \00" @.str553 = private unnamed_addr constant [2 x i8] c")\00" -@.str554 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str554 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str555 = private unnamed_addr constant [10 x i8] c"file_open\00" @.str556 = private unnamed_addr constant [21 x i8] c"call ptr @fopen(ptr \00" @.str557 = private unnamed_addr constant [7 x i8] c", ptr \00" @.str558 = private unnamed_addr constant [2 x i8] c")\00" -@.str559 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str559 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str560 = private unnamed_addr constant [10 x i8] c"file_read\00" @.str561 = private unnamed_addr constant [11 x i8] c"file_write\00" @.str562 = private unnamed_addr constant [10 x i8] c"zext i32 \00" @@ -709,10 +709,10 @@ declare void @win_close() @.str608 = private unnamed_addr constant [5 x i8] c"void\00" @.str609 = private unnamed_addr constant [12 x i8] c"file_stderr\00" @.str610 = private unnamed_addr constant [25 x i8] c"load ptr, ptr @__stderrp\00" -@.str611 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str611 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str612 = private unnamed_addr constant [12 x i8] c"file_stdout\00" @.str613 = private unnamed_addr constant [25 x i8] c"load ptr, ptr @__stdoutp\00" -@.str614 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str614 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str615 = private unnamed_addr constant [4 x i8] c"run\00" @.str616 = private unnamed_addr constant [22 x i8] c"call i32 @system(ptr \00" @.str617 = private unnamed_addr constant [2 x i8] c")\00" @@ -755,7 +755,7 @@ declare void @win_close() @.str654 = private unnamed_addr constant [35 x i8] c" = getelementptr inbounds i8, ptr \00" @.str655 = private unnamed_addr constant [7 x i8] c", i32 \00" @.str656 = private unnamed_addr constant [2 x i8] c"\0A\00" -@.str657 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str657 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str658 = private unnamed_addr constant [10 x i8] c"read_char\00" @.str659 = private unnamed_addr constant [20 x i8] c"call i32 @getchar()\00" @.str660 = private unnamed_addr constant [4 x i8] c"int\00" @@ -2585,7 +2585,7 @@ declare void @win_close() @.str2484 = private unnamed_addr constant [8 x i8] c" to i64\00" @.str2485 = private unnamed_addr constant [22 x i8] c"call ptr @malloc(i64 \00" @.str2486 = private unnamed_addr constant [2 x i8] c")\00" -@.str2487 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str2487 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str2488 = private unnamed_addr constant [6 x i8] c"words\00" @.str2489 = private unnamed_addr constant [9 x i8] c"mul i32 \00" @.str2490 = private unnamed_addr constant [4 x i8] c", 4\00" @@ -3593,7 +3593,7 @@ declare void @win_close() @.str3492 = private unnamed_addr constant [8 x i8] c" to i64\00" @.str3493 = private unnamed_addr constant [22 x i8] c"call ptr @malloc(i64 \00" @.str3494 = private unnamed_addr constant [2 x i8] c")\00" -@.str3495 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str3495 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str3496 = private unnamed_addr constant [6 x i8] c"words\00" @.str3497 = private unnamed_addr constant [9 x i8] c"mul i32 \00" @.str3498 = private unnamed_addr constant [4 x i8] c", 4\00" @@ -3707,7 +3707,7 @@ declare void @win_close() @.str3606 = private unnamed_addr constant [6 x i8] c"fixed\00" @.str3607 = private unnamed_addr constant [5 x i8] c"bool\00" @.str3608 = private unnamed_addr constant [5 x i8] c"null\00" -@.str3609 = private unnamed_addr constant [4 x i8] c"ptr\00" +@.str3609 = private unnamed_addr constant [8 x i8] c"pointer\00" @.str3610 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_slice(ptr \00" @.str3611 = private unnamed_addr constant [7 x i8] c", i32 \00" @.str3612 = private unnamed_addr constant [7 x i8] c", i32 \00" diff --git a/selfhost/main.ludic b/selfhost/main.ludic index fd1283ef..60183d42 100644 --- a/selfhost/main.ludic +++ b/selfhost/main.ludic @@ -15,7 +15,7 @@ # reseed.sh rely on, so the bootstrap is untouched. # basename: the part of a path after the last '/'. -function base_name(path: ptr) -> ptr { +function base_name(path: pointer) -> pointer { var last = 0 - 1 var i = 0 while path[i] != 0 { if path[i] == 47 { last = i }; i = i + 1 } @@ -23,7 +23,7 @@ function base_name(path: ptr) -> ptr { } # drop a trailing ".ludic" if present -function strip_ludic(name: ptr) -> ptr { +function strip_ludic(name: pointer) -> pointer { let n = len(name) if n > 6 { if (name[n - 6..n] == ".ludic") { return name[0..n - 6] } @@ -32,21 +32,21 @@ function strip_ludic(name: ptr) -> ptr { } # env var with a fallback when unset -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 } # guarantee a directory string ends in '/' so path_join concatenates cleanly -function ensure_slash(d: ptr) -> ptr { +function ensure_slash(d: pointer) -> pointer { let n = len(d) if n == 0 { return d } if d[n - 1] == 47 { return d } return (d + ("/")) } -function die(msg: ptr) -> void { +function die(msg: pointer) -> void { file_write(file_stderr(), msg, len(msg)) exit(1) } diff --git a/selfhost/parse.ludic b/selfhost/parse.ludic index 34ff3ac2..5fb61480 100644 --- a/selfhost/parse.ludic +++ b/selfhost/parse.ludic @@ -4,15 +4,15 @@ var pi: int = 0 var prog: []Node # the top-level declarations -var g_game_name: ptr # the `game`/`module` name +var g_game_name: pointer # the `game`/`module` name function cur() -> Tok { return toks[pi] } function pk(o: int) -> Tok { return toks[pi + o] } -function is_op(v: ptr) -> bool { let t = toks[pi]; return t.kind == TK_OP and (t.text == v) } -function is_id(v: ptr) -> bool { let t = toks[pi]; return t.kind == TK_ID and (t.text == v) } -function is_kw(v: ptr) -> bool { return is_id(v) } +function is_op(v: pointer) -> bool { let t = toks[pi]; return t.kind == TK_OP and (t.text == v) } +function is_id(v: pointer) -> bool { let t = toks[pi]; return t.kind == TK_ID and (t.text == v) } +function is_kw(v: pointer) -> bool { return is_id(v) } -function perr(msg: ptr) -> void { +function perr(msg: pointer) -> void { let e = file_stderr() file_write(e, "ludicc(self): parse error: ", 27) file_write(e, msg, len(msg)) @@ -20,8 +20,8 @@ function perr(msg: ptr) -> void { exit(1) } -function eat_op(v: ptr) -> void { if not is_op(v) { perr(v) }; pi = pi + 1 } -function eat_id() -> ptr { +function eat_op(v: pointer) -> void { if not is_op(v) { perr(v) }; pi = pi + 1 } +function eat_id() -> pointer { let t = toks[pi] if t.kind != TK_ID { perr("expected identifier") } pi = pi + 1 @@ -30,7 +30,7 @@ function eat_id() -> ptr { function skipnl() -> void { while toks[pi].kind == TK_NL { pi = pi + 1 } } # a type: `[]T` slice, or a plain name (int/ptr/str/bool/struct) -function ptype() -> ptr { +function ptype() -> pointer { if is_op("[") { pi = pi + 1 eat_op("]") @@ -70,7 +70,7 @@ function args_call(call: Node) -> void { # ---- string interpolation -------------------------------------------------- # `text {expr} text` desugars to a `+` chain of string literals and `string(expr)` # holes, so it reuses the string-concat operator and needs no new runtime. -function interp_lit(buf: ptr, len: int) -> Node { let n = node(E_STR); n.s = buf[0..0 + len]; return n } +function interp_lit(buf: pointer, len: int) -> Node { let n = node(E_STR); n.s = buf[0..0 + len]; return n } function interp_add(acc: Node, part: Node) -> Node { if acc == null { return part } return mkbin("+", acc, part) @@ -78,14 +78,14 @@ function interp_add(acc: Node, part: Node) -> Node { function interp_str(e: Node) -> Node { # wrap a hole in string(...) let c = node(E_CALL); let id = node(E_ID); id.s = "string"; c.a = id; push(c.kids, e); return c } -function parse_hole(inner: ptr) -> Node { # re-lex+parse an embedded expression +function parse_hole(inner: pointer) -> Node { # re-lex+parse an embedded expression let saved_toks = toks; let saved_pi = pi lex(inner); pi = 0; skipnl() let e = expr() toks = saved_toks; pi = saved_pi return e } -function parse_interp(raw: ptr) -> Node { +function parse_interp(raw: pointer) -> Node { let n = len(raw) var acc: Node = null let lit = bytes(n + 1) @@ -176,7 +176,7 @@ function p_unary() -> Node { return p_postfix() } -function mkbin(op: ptr, l: Node, r: Node) -> Node { let b = node(E_BIN); b.s = op; b.a = l; b.b = r; return b } +function mkbin(op: pointer, l: Node, r: Node) -> Node { let b = node(E_BIN); b.s = op; b.a = l; b.b = r; return b } # precedence (Go-style, so `flags & MASK == 0` needs no parens): shifts and `&` # bind like `*`; `|` and `^` bind like `+`; both tighter than comparison. @@ -357,22 +357,22 @@ function parse_fn() -> Node { function parse_main() -> Node { pi = pi + 1; let n = node(N_MAIN); n.a = block(); return n } # directory part of a path, including the trailing '/', or "" if none -function dir_of(path: ptr) -> ptr { +function dir_of(path: pointer) -> pointer { var last = 0 - 1 var i = 0 while path[i] != 0 { if path[i] == 47 { last = i }; i = i + 1 } if last < 0 { return "" } return path[0..0 + (last + 1)] } -function path_join(dir: ptr, rel: ptr) -> ptr { +function path_join(dir: pointer, rel: pointer) -> pointer { if rel[0] == 47 { return rel } # absolute return (dir + rel) } -var loaded_paths: []ptr -var cur_dir: ptr +var loaded_paths: []pointer +var cur_dir: pointer -function already_loaded(full: ptr) -> bool { +function already_loaded(full: pointer) -> bool { var i = 0 while i < len(loaded_paths) { if (loaded_paths[i] == full) { return true }; i = i + 1 } return false @@ -384,20 +384,20 @@ function already_loaded(full: ptr) -> bool { function parse_one_decl() -> void { var is_export = false var qspec: Node = null - var onspawn_model: ptr = null - var ondespawn_model: ptr = null - var ondespawn_reason: ptr = null # @OnDespawn(M, reason: r) — LC1 teardown reason binding - var onattach_prop: ptr = null - var ondetach_prop: ptr = null - var onenable_prop: ptr = null - var ondisable_prop: ptr = null - var on_event: ptr = null # @On(Event) — a compile-time event listener + var onspawn_model: pointer = null + var ondespawn_model: pointer = null + var ondespawn_reason: pointer = null # @OnDespawn(M, reason: r) — LC1 teardown reason binding + var onattach_prop: pointer = null + var ondetach_prop: pointer = null + var onenable_prop: pointer = null + var ondisable_prop: pointer = null + var on_event: pointer = null # @On(Event) — a compile-time event listener var is_public = false # @Public — promote a lifecycle hook to an event - var hook_phase: ptr = null # @OnStart / @OnQuit override the phase + var hook_phase: pointer = null # @OnStart / @OnQuit override the phase var is_sync_prop = false # @Sync property P — every field replicates (NETWORKING N2) var is_owned = false # @Owned model M — entities carry a network owner (N3) - var role: ptr = null # @Server / @Predicted — a handler's network role (N5) - var remote_dir: ptr = null # @ToServer / @ToClients — a remote event's direction (N4) + var role: pointer = null # @Server / @Predicted — a handler's network role (N5) + var remote_dir: pointer = null # @ToServer / @ToClients — a remote event's direction (N4) while is_op("@") { pi = pi + 1; let a = eat_id() # collect a leading @annotation if (a == "export") { is_export = true } @@ -489,7 +489,7 @@ function parse_one_decl() -> void { } # lex and parse an imported fragment into `prog`, saving/restoring lexer state -function do_import(rel: ptr) -> void { +function do_import(rel: pointer) -> void { let full = path_join(cur_dir, rel) if already_loaded(full) { return } push(loaded_paths, full) @@ -528,8 +528,8 @@ function parse_program() -> void { g_start_scene = 0 g_events = new []Node g_onlisten = new []Node - g_toggled_layers = new []ptr - loaded_paths = new []ptr + g_toggled_layers = new []pointer + loaded_paths = new []pointer skipnl() g_game_name = "Ludic" # imports may precede the program block diff --git a/selfhost/str.ludic b/selfhost/str.ludic index d7a6f07c..f9a2fa43 100644 --- a/selfhost/str.ludic +++ b/selfhost/str.ludic @@ -13,7 +13,7 @@ function char_is_alpha(c: int) -> bool { function char_is_alnum(c: int) -> bool { return char_is_alpha(c) or char_is_digit(c) } # integer -> fresh decimal string -function itoa(v: int) -> ptr { +function itoa(v: int) -> pointer { if v == 0 { let z = bytes(2); z[0] = 48; z[1] = 0; return z } var neg = false var x = v diff --git a/tools/atlas.ludic b/tools/atlas.ludic index c2ef93ec..e12791c9 100644 --- a/tools/atlas.ludic +++ b/tools/atlas.ludic @@ -47,9 +47,9 @@ game Atlas { return buf } - var atlas_scratch: ptr = ptr_null() + var atlas_scratch: pointer = ptr_null() - function atlas_buf() -> ptr { + function atlas_buf() -> pointer { if ptr_is_null(atlas_scratch) { atlas_scratch = mem_alloc(512) } return atlas_scratch } diff --git a/tools/docgen/inventory.json b/tools/docgen/inventory.json index db92f160..16feaa50 100644 --- a/tools/docgen/inventory.json +++ b/tools/docgen/inventory.json @@ -324,8 +324,8 @@ "type-fixed", "type-fixeds", "type-int", - "type-ptr", - "type-ptrs", + "type-pointer", + "type-pointers", "type-slices", "type-string", "type-void", diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt index 3d2aa523..c826ec9a 100644 --- a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt +++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt @@ -52,7 +52,7 @@ object LudicVocabulary { "enable", "disable", "match", "machine", "state", "become", "where", "and", "or", "not", "break", "continue", "new", "emit", "cancel" ) - val PRIMITIVES = setOf("int", "long", "fixed", "bool", "entity", "string", "ptr", "byte", "words", "fixeds", "ptrs", "void") + val PRIMITIVES = setOf("int", "long", "fixed", "bool", "entity", "string", "pointer", "byte", "words", "fixeds", "pointers", "void") val PHASES = setOf("Start", "Input", "FixedUpdate", "Update", "LateUpdate", "Render") val WIDGETS = setOf("panel", "col", "row", "label", "button", "image", "spacer") diff --git a/tools/editors/shared/ludic.tmLanguage.json b/tools/editors/shared/ludic.tmLanguage.json index 7ec5a746..8f08aa12 100644 --- a/tools/editors/shared/ludic.tmLanguage.json +++ b/tools/editors/shared/ludic.tmLanguage.json @@ -177,7 +177,7 @@ { "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" }, { "name": "keyword.other.ludic", "match": "\\b(import|extern)\\b" }, { "name": "storage.type.ludic", "match": "\\b(program|property|model|enum|ui|const|var|let|function|handler|entry|state)\\b" }, - { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|ptr|byte|words|fixeds|ptrs|void)\\b" }, + { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|pointer|byte|words|fixeds|pointers|void)\\b" }, { "name": "constant.language.boolean.ludic", "match": "\\b(true|false|null)\\b" }, { "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" } ] diff --git a/tools/editors/vscode/syntaxes/ludic.tmLanguage.json b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json index 7ec5a746..8f08aa12 100644 --- a/tools/editors/vscode/syntaxes/ludic.tmLanguage.json +++ b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json @@ -177,7 +177,7 @@ { "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" }, { "name": "keyword.other.ludic", "match": "\\b(import|extern)\\b" }, { "name": "storage.type.ludic", "match": "\\b(program|property|model|enum|ui|const|var|let|function|handler|entry|state)\\b" }, - { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|ptr|byte|words|fixeds|ptrs|void)\\b" }, + { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|pointer|byte|words|fixeds|pointers|void)\\b" }, { "name": "constant.language.boolean.ludic", "match": "\\b(true|false|null)\\b" }, { "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" } ] diff --git a/tools/ludic-tools/fmt.ludic b/tools/ludic-tools/fmt.ludic index 02489075..e3e08d24 100644 --- a/tools/ludic-tools/fmt.ludic +++ b/tools/ludic-tools/fmt.ludic @@ -28,7 +28,7 @@ program LudicFmt { const LT_ERR: int = 14 # ---- tiny stdio + string helpers (self-contained) ---- - function read_file(path: string) -> ptr { + function read_file(path: string) -> pointer { let f = file_open(path, "rb") if (f == null) { return null } file_seek(f, 0, 2) @@ -40,7 +40,7 @@ program LudicFmt { file_close(f) return buf } - function cstr_len(s: ptr) -> int { var n = 0; while s[n] != 0 { n = n + 1 }; return n } + function cstr_len(s: pointer) -> int { var n = 0; while s[n] != 0 { n = n + 1 }; return n } function char_is_digit(c: int) -> bool { return c >= 48 and c <= 57 } function char_is_alpha(c: int) -> bool { if c >= 65 and c <= 90 { return true } @@ -49,7 +49,7 @@ program LudicFmt { } function char_is_alnum(c: int) -> bool { return char_is_alpha(c) or char_is_digit(c) } function char_is_hex(c: int) -> bool { return char_is_digit(c) or (c >= 97 and c <= 102) or (c >= 65 and c <= 70) } - function itoa(v: int) -> ptr { + function itoa(v: int) -> pointer { if v == 0 { let z = bytes(2); z[0] = 48; z[1] = 0; return z } var neg = false; var x = v if x < 0 { neg = true; x = 0 - x } @@ -66,7 +66,7 @@ program LudicFmt { } # ---- a growable byte buffer ---- - property Buf { data: ptr = null, len: int = 0, cap: int = 0 } + property Buf { data: pointer = null, len: int = 0, cap: int = 0 } function buf_new() -> Buf { let b = new Buf; b.cap = 256; b.data = bytes(b.cap); b.len = 0; return b } function buf_ensure(b: Buf, extra: int) -> void { if b.len + extra + 1 <= b.cap { return } @@ -74,14 +74,14 @@ program LudicFmt { b.data = resize(b.data, b.cap) } function buf_putc(b: Buf, c: int) -> void { buf_ensure(b, 1); b.data[b.len] = c; b.len = b.len + 1 } - function buf_puts(b: Buf, s: ptr) -> void { var i = 0; while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 } } + function buf_puts(b: Buf, s: pointer) -> void { var i = 0; while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 } } function buf_indent(b: Buf, n: int) -> void { var i = 0; while i < n { buf_putc(b, 32); i = i + 1 } } - function buf_str(b: Buf) -> ptr { b.data[b.len] = 0; return b.data } + function buf_str(b: Buf) -> pointer { b.data[b.len] = 0; return b.data } # append src[a..b) raw - function buf_addrange(b: Buf, s: ptr, a: int, e: int) -> void { var k = a; while k < e { buf_putc(b, s[k]); k = k + 1 } } + function buf_addrange(b: Buf, s: pointer, a: int, e: int) -> void { var k = a; while k < e { buf_putc(b, s[k]); k = k + 1 } } # ---- the token stream (parallel slices) ---- - var src: ptr = null + var src: pointer = null var tk_kind: []int var tk_start: []int var tk_end: []int @@ -90,19 +90,19 @@ program LudicFmt { function ntok() -> int { return len(tk_kind) } function tok_len(i: int) -> int { return tk_end[i] - tk_start[i] } - function tok_text(i: int) -> ptr { return src[tk_start[i]..tk_end[i]] } + function tok_text(i: int) -> pointer { return src[tk_start[i]..tk_end[i]] } function push_tok(k: int, st: int, en: int, ln: int) -> void { push(tk_kind, k); push(tk_start, st); push(tk_end, en); push(tk_line, ln) } # ---- vocabulary classifiers ---- - function is_type_word(w: ptr) -> bool { + function is_type_word(w: pointer) -> bool { return (w == "int") or (w == "long") or (w == "fixed") or (w == "bool") or (w == "entity") or (w == "str") or (w == "ptr") or (w == "byte") or (w == "words") or (w == "fixeds") or (w == "ptrs") or (w == "void") } - function is_phase_word(w: ptr) -> bool { + function is_phase_word(w: pointer) -> bool { return (w == "Start") or (w == "Input") or (w == "FixedUpdate") or (w == "Update") or (w == "LateUpdate") or (w == "Render") } - function is_keyword_word(w: ptr) -> bool { + function is_keyword_word(w: pointer) -> bool { if (w == "program") or (w == "import") or (w == "property") or (w == "model") or (w == "enum") or (w == "ui") { return true } if (w == "const") or (w == "var") or (w == "function") or (w == "extern") or (w == "handler") or (w == "entry") or (w == "event") or (w == "scene") { return true } if (w == "phase") or (w == "query") or (w == "on") or (w == "cancellable") or (w == "public") or (w == "layer") or (w == "start") { return true } @@ -111,7 +111,7 @@ program LudicFmt { if (w == "and") or (w == "or") or (w == "not") or (w == "break") or (w == "continue") or (w == "new") or (w == "emit") or (w == "cancel") { return true } return false } - function is_clause_word(w: ptr) -> bool { + function is_clause_word(w: pointer) -> bool { return (w == "phase") or (w == "query") or (w == "reads") or (w == "writes") or (w == "needs") or (w == "uses") or (w == "requires") or (w == "ensures") or (w == "invariant") or (w == "effects") } @@ -129,7 +129,7 @@ program LudicFmt { return c == 43 or c == 45 or c == 42 or c == 47 or c == 37 or c == 60 or c == 62 or c == 61 or c == 40 or c == 41 or c == 123 or c == 125 or c == 91 or c == 93 or c == 44 or c == 58 or c == 46 or c == 33 or c == 64 or c == 59 } - function lex(s: ptr) -> void { + function lex(s: pointer) -> void { src = s tk_kind = new []int; tk_start = new []int; tk_end = new []int; tk_line = new []int linestart = new []int @@ -394,7 +394,7 @@ program LudicFmt { var g_info: int = 0 var g_marker: int = 0 # detect a fence at line offset i; sets g_flen/g_info/g_marker; returns bool - function md_fence_at(s: ptr, i: int) -> bool { + function md_fence_at(s: pointer, i: int) -> bool { var j = i; while s[j] == 32 { j = j + 1 } let m = s[j] if m != 96 and m != 126 { return false } # ` or ~ @@ -403,16 +403,16 @@ program LudicFmt { g_flen = n; g_info = j; g_marker = m return true } - function md_info_is_ludic(s: ptr, at: int) -> bool { + function md_info_is_ludic(s: pointer, at: int) -> bool { var a = at; while s[a] == 32 or s[a] == 9 { a = a + 1 } # case-insensitive "ludic" if not (((s[a] == 108 or s[a] == 76)) and ((s[a + 1] == 117 or s[a + 1] == 85)) and ((s[a + 2] == 100 or s[a + 2] == 68)) and ((s[a + 3] == 105 or s[a + 3] == 73)) and ((s[a + 4] == 99 or s[a + 4] == 67))) { return false } let af = s[a + 5] return af == 0 or af == 10 or af == 32 or af == 9 or af == 13 } - function line_end(s: ptr, i: int) -> int { var e = i; while s[e] != 0 and s[e] != 10 { e = e + 1 }; return e } + function line_end(s: pointer, i: int) -> int { var e = i; while s[e] != 0 and s[e] != 10 { e = e + 1 }; return e } - function format_markdown(s: ptr, indent_width: int) -> Buf { + function format_markdown(s: pointer, indent_width: int) -> Buf { let o = buf_new() var i = 0 while s[i] != 0 { @@ -478,14 +478,14 @@ program LudicFmt { } # ---- ends-with helpers for extension detection ---- - function ends_with(s: ptr, suf: ptr) -> bool { + function ends_with(s: pointer, suf: pointer) -> bool { let n = cstr_len(s); let m = cstr_len(suf) if m > n { return false } return (s[n - m..n] == suf) } # ---- stdin slurp (for `-`) ---- - function slurp_stdin() -> ptr { + function slurp_stdin() -> pointer { let b = buf_new() var c = read_char() while c >= 0 { buf_putc(b, c); c = read_char() } @@ -493,14 +493,14 @@ program LudicFmt { } # format one source string according to its kind (markdown vs ludic) - function format_source(text: ptr, is_md: bool, indent_width: int) -> ptr { + function format_source(text: pointer, is_md: bool, indent_width: int) -> pointer { if is_md { let m = format_markdown(text, indent_width); return buf_str(m) } lex(text) let f = format(indent_width) return buf_str(f) } - function streq(a: ptr, b: ptr) -> bool { return (a == b) } + function streq(a: pointer, b: pointer) -> bool { return (a == b) } entry { var write = false @@ -509,7 +509,7 @@ program LudicFmt { var quiet = false var changed = false var failed = false - let files = new []ptr + let files = new []pointer var ai = 1 while ai < arg_count() { let a = arg(ai) diff --git a/tools/ludic-tools/lsp.ludic b/tools/ludic-tools/lsp.ludic index e431d6e6..820ef9d4 100644 --- a/tools/ludic-tools/lsp.ludic +++ b/tools/ludic-tools/lsp.ludic @@ -72,7 +72,7 @@ program LudicLsp { const SC_UNKNOWN: int = 24 # ---- tiny helpers ---- - 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) @@ -84,7 +84,7 @@ program LudicLsp { file_close(f) return buf } - function cstr_len(s: ptr) -> int { var n = 0; while s[n] != 0 { n = n + 1 }; return n } + function cstr_len(s: pointer) -> int { var n = 0; while s[n] != 0 { n = n + 1 }; return n } function char_is_digit(c: int) -> bool { return c >= 48 and c <= 57 } function char_is_alpha(c: int) -> bool { if c >= 65 and c <= 90 { return true } @@ -93,7 +93,7 @@ program LudicLsp { } function char_is_alnum(c: int) -> bool { return char_is_alpha(c) or char_is_digit(c) } function char_is_hex(c: int) -> bool { return char_is_digit(c) or (c >= 97 and c <= 102) or (c >= 65 and c <= 70) } - function itoa(v: int) -> ptr { + function itoa(v: int) -> pointer { if v == 0 { let z = bytes(2); z[0] = 48; z[1] = 0; return z } var neg = false; var x = v if x < 0 { neg = true; x = 0 - x } @@ -108,7 +108,7 @@ program LudicLsp { out[total] = 0 return out } - function atoi(s: ptr) -> int { + function atoi(s: pointer) -> int { var n = 0; var i = 0; var neg = false while s[i] == 32 or s[i] == 9 { i = i + 1 } if s[i] == 45 { neg = true; i = i + 1 } @@ -118,7 +118,7 @@ program LudicLsp { } # ---- growable byte buffer ---- - property Buf { data: ptr = null, len: int = 0, cap: int = 0 } + property Buf { data: pointer = null, len: int = 0, cap: int = 0 } function buf_new() -> Buf { let b = new Buf; b.cap = 256; b.data = bytes(b.cap); b.len = 0; return b } function buf_ensure(b: Buf, extra: int) -> void { if b.len + extra + 1 <= b.cap { return } @@ -126,20 +126,20 @@ program LudicLsp { b.data = resize(b.data, b.cap) } function buf_putc(b: Buf, c: int) -> void { buf_ensure(b, 1); b.data[b.len] = c; b.len = b.len + 1 } - function buf_puts(b: Buf, s: ptr) -> void { var i = 0; while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 } } + function buf_puts(b: Buf, s: pointer) -> void { var i = 0; while s[i] != 0 { buf_putc(b, s[i]); i = i + 1 } } function buf_puti(b: Buf, n: int) -> void { buf_puts(b, itoa(n)) } - function buf_addrange(b: Buf, s: ptr, a: int, e: int) -> void { var k = a; while k < e { buf_putc(b, s[k]); k = k + 1 } } - function buf_str(b: Buf) -> ptr { b.data[b.len] = 0; return b.data } + function buf_addrange(b: Buf, s: pointer, a: int, e: int) -> void { var k = a; while k < e { buf_putc(b, s[k]); k = k + 1 } } + function buf_str(b: Buf) -> pointer { b.data[b.len] = 0; return b.data } # ---- string helpers ---- - function streq(a: ptr, b: ptr) -> bool { return (a == b) } - function concat3(a: ptr, b: ptr, c: ptr) -> ptr { return ((a + b) + c) } - function ends_with(s: ptr, suf: ptr) -> bool { + function streq(a: pointer, b: pointer) -> bool { return (a == b) } + function concat3(a: pointer, b: pointer, c: pointer) -> pointer { return ((a + b) + c) } + function ends_with(s: pointer, suf: pointer) -> bool { let n = cstr_len(s); let m = cstr_len(suf) if m > n { return false } return (s[n - m..n] == suf) } - function starts_with(s: ptr, pre: ptr) -> bool { + function starts_with(s: pointer, pre: pointer) -> bool { let m = cstr_len(pre) if m > cstr_len(s) { return false } return (s[0..m] == pre) @@ -150,10 +150,10 @@ program LudicLsp { # ============================================================================ property Sym { kind: int = 0 - name: ptr = null - ty: ptr = null - detail: ptr = null - doc: ptr = null + name: pointer = null + ty: pointer = null + detail: pointer = null + doc: pointer = null tok: int = 0 start: int = 0 end: int = 0 @@ -163,15 +163,15 @@ program LudicLsp { exported: int = 0 } property Doc { - path: ptr = null - uri: ptr = null - raw: ptr = null - text: ptr = null + path: pointer = null + uri: pointer = null + raw: pointer = null + text: pointer = null is_md: int = 0 is_unit: int = 0 is_module: int = 0 - unit: ptr = null - src: ptr = null + unit: pointer = null + src: pointer = null tk_kind: []int tk_start: []int tk_end: []int @@ -180,14 +180,14 @@ program LudicLsp { tmatch: []int cls: []int syms: []Sym - imports: []ptr + imports: []pointer had_diags: int = 0 isopen: int = 0 version: int = 0 } var g_docs: []Doc - var g_root: ptr = null + var g_root: pointer = null var g_shutdown: int = 0 # ---- the lexer, over a Doc ---- @@ -203,13 +203,13 @@ program LudicLsp { function is_op1(c: int) -> bool { return c == 43 or c == 45 or c == 42 or c == 47 or c == 37 or c == 60 or c == 62 or c == 61 or c == 40 or c == 41 or c == 123 or c == 125 or c == 91 or c == 93 or c == 44 or c == 58 or c == 46 or c == 33 or c == 64 or c == 59 } - function is_type_word(w: ptr) -> bool { - return (w == "int") or (w == "long") or (w == "fixed") or (w == "bool") or (w == "entity") or (w == "string") or (w == "ptr") or (w == "byte") or (w == "words") or (w == "fixeds") or (w == "ptrs") or (w == "void") + function is_type_word(w: pointer) -> bool { + return (w == "int") or (w == "long") or (w == "fixed") or (w == "bool") or (w == "entity") or (w == "string") or (w == "pointer") or (w == "byte") or (w == "words") or (w == "fixeds") or (w == "pointers") or (w == "void") } - function is_phase_word(w: ptr) -> bool { + function is_phase_word(w: pointer) -> bool { return (w == "Start") or (w == "Input") or (w == "FixedUpdate") or (w == "Update") or (w == "LateUpdate") or (w == "Render") } - function is_keyword_word(w: ptr) -> bool { + function is_keyword_word(w: pointer) -> bool { if (w == "program") or (w == "import") or (w == "property") or (w == "model") or (w == "enum") or (w == "ui") { return true } if (w == "const") or (w == "var") or (w == "function") or (w == "extern") or (w == "handler") or (w == "entry") or (w == "event") or (w == "scene") { return true } if (w == "phase") or (w == "query") or (w == "on") or (w == "cancellable") or (w == "public") or (w == "layer") or (w == "start") { return true } @@ -218,7 +218,7 @@ program LudicLsp { if (w == "and") or (w == "or") or (w == "not") or (w == "break") or (w == "continue") or (w == "new") or (w == "emit") or (w == "cancel") { return true } return false } - function is_widget_word(w: ptr) -> bool { + function is_widget_word(w: pointer) -> bool { return (w == "panel") or (w == "col") or (w == "row") or (w == "label") or (w == "button") or (w == "image") or (w == "spacer") } @@ -267,13 +267,13 @@ program LudicLsp { function ntok(D: Doc) -> int { return len(D.tk_kind) } function tlen(D: Doc, i: int) -> int { return D.tk_end[i] - D.tk_start[i] } - function ttext(D: Doc, i: int) -> ptr { return D.src[D.tk_start[i]..D.tk_end[i]] } - function tis(D: Doc, i: int, s: ptr) -> bool { if i < 0 or i >= ntok(D) { return false }; return (ttext(D, i) == s) } + function ttext(D: Doc, i: int) -> pointer { return D.src[D.tk_start[i]..D.tk_end[i]] } + function tis(D: Doc, i: int, s: pointer) -> bool { if i < 0 or i >= ntok(D) { return false }; return (ttext(D, i) == s) } function next_sig(D: Doc, i: int) -> int { var j = i + 1; while j < ntok(D) { let k = D.tk_kind[j]; if k != LT_NL and k != LT_COMMENT { return j }; j = j + 1 }; return 0 - 1 } function prev_sig(D: Doc, i: int) -> int { var j = i - 1; while j >= 0 { let k = D.tk_kind[j]; if k != LT_NL and k != LT_COMMENT { return j }; j = j - 1 }; return 0 - 1 } # ---- positions (UTF-16 for LSP) ---- - function utf16_len(s: ptr, a: int, nbytes: int) -> int { + function utf16_len(s: pointer, a: int, nbytes: int) -> int { var u = 0; var i = 0 while i < nbytes { let c = s[a + i] @@ -342,7 +342,7 @@ program LudicLsp { } # ---- doc comment: the comment block directly above a declaration ---- - function collect_doc(D: Doc, decl_tok: int) -> ptr { + function collect_doc(D: Doc, decl_tok: int) -> pointer { var line = D.tk_line[decl_tok] var first = 0 - 1 var i = decl_tok - 1 @@ -380,10 +380,10 @@ program LudicLsp { var pi: int = 0 function pk() -> int { if pi < ntok(pD) { return pD.tk_kind[pi] }; return LT_EOF } - function pis(s: ptr) -> bool { return tis(pD, pi, s) } + function pis(s: pointer) -> bool { return tis(pD, pi, s) } function pskipnl() -> void { while pi < ntok(pD) and (pk() == LT_NL or pk() == LT_COMMENT) { pi = pi + 1 } } function padv() -> void { if pi < ntok(pD) { pi = pi + 1 }; pskipnl() } - function pword() -> ptr { if pi < ntok(pD) { return ttext(pD, pi) }; return "" } + function pword() -> pointer { if pi < ntok(pD) { return ttext(pD, pi) }; return "" } function pname() -> int { let k = pk() if k == LT_ID or k == LT_TYPE or k == LT_PHASE or k == LT_KW or k == LT_BOOL { let t = pi; padv(); return t } @@ -797,7 +797,7 @@ program LudicLsp { function parse_doc(D: Doc) -> void { D.syms = new []Sym - D.imports = new []ptr + D.imports = new []pointer D.is_unit = 0; D.is_module = 0; D.unit = "" pD = D; pi = 0 pskipnl() @@ -848,7 +848,7 @@ program LudicLsp { if l >= 97 and l <= 102 { return l - 97 + 10 } return 0 - 1 } - function uri_to_path(uri: ptr) -> ptr { + function uri_to_path(uri: pointer) -> pointer { var s = uri if starts_with(uri, "file://") { s = uri[7..cstr_len(uri)] } let n = cstr_len(s) @@ -866,7 +866,7 @@ program LudicLsp { return c == 45 or c == 46 or c == 126 or c == 47 # - . ~ / } function hexch(n: int) -> int { if n < 10 { return 48 + n }; return 55 + n } - function path_to_uri(path: ptr) -> ptr { + function path_to_uri(path: pointer) -> pointer { let out = buf_new() buf_puts(out, "file://") var i = 0 @@ -878,7 +878,7 @@ program LudicLsp { } return buf_str(out) } - function dirname(p: ptr) -> ptr { + function dirname(p: pointer) -> pointer { var last = 0 - 1 var i = 0 while p[i] != 0 { if p[i] == 47 { last = i }; i = i + 1 } @@ -886,10 +886,10 @@ program LudicLsp { if last == 0 { return "/" } return p[0..last] } - function normpath(p: ptr) -> ptr { + function normpath(p: pointer) -> pointer { let n = cstr_len(p) let abs = (n > 0 and p[0] == 47) - let list = new []ptr + let list = new []pointer var cnt = 0 var i = 0 while i < n { @@ -914,16 +914,16 @@ program LudicLsp { while k < cnt { if k > 0 { buf_putc(out, 47) }; buf_puts(out, list[k]); k = k + 1 } return buf_str(out) } - function join_path(dir: ptr, rel: ptr) -> ptr { + function join_path(dir: pointer, rel: pointer) -> pointer { if rel[0] == 47 { return normpath(rel) } return normpath(concat3(dir, "/", rel)) } # ---- markdown scrub: blank everything outside a ```ludic fence ---- - function word_ludic_at(s: ptr, at: int) -> bool { + function word_ludic_at(s: pointer, at: int) -> bool { return ((s[at] == 108 or s[at] == 76)) and ((s[at + 1] == 117 or s[at + 1] == 85)) and ((s[at + 2] == 100 or s[at + 2] == 68)) and ((s[at + 3] == 105 or s[at + 3] == 73)) and ((s[at + 4] == 99 or s[at + 4] == 67)) } - function scrub_markdown(src: ptr) -> ptr { + function scrub_markdown(src: pointer) -> pointer { let n = cstr_len(src) let out = bytes(n + 1) var c0 = 0 @@ -974,7 +974,7 @@ program LudicLsp { } # ---- documents ---- - function set_text(D: Doc, raw: ptr) -> void { + function set_text(D: Doc, raw: pointer) -> void { D.raw = raw if D.is_md == 1 { D.text = scrub_markdown(raw) } else { D.text = raw } D.src = D.text @@ -988,24 +988,24 @@ program LudicLsp { let N = ntok(D) while i < N { push(D.cls, SC_NONE); i = i + 1 } } - function new_doc(path: ptr, text: ptr) -> Doc { + function new_doc(path: pointer, text: pointer) -> Doc { let D = new Doc D.path = normpath(path) D.uri = path_to_uri(D.path) D.is_md = 0 if ends_with(D.path, ".md") or ends_with(D.path, ".markdown") { D.is_md = 1 } - D.syms = new []Sym; D.imports = new []ptr; D.unit = "" + D.syms = new []Sym; D.imports = new []pointer; D.unit = "" set_text(D, text) reindex(D) return D } - function by_path(path: ptr) -> Doc { + function by_path(path: pointer) -> Doc { let p = normpath(path) var i = 0 while i < len(g_docs) { if (g_docs[i].path == p) { return g_docs[i] }; i = i + 1 } return null } - function by_uri(uri: ptr) -> Doc { + function by_uri(uri: pointer) -> Doc { let p = uri_to_path(uri) let D = by_path(p) if (D != null) { return D } @@ -1013,7 +1013,7 @@ program LudicLsp { while i < len(g_docs) { if (g_docs[i].uri == uri) { return g_docs[i] }; i = i + 1 } return null } - function ensure_doc(path: ptr) -> Doc { + function ensure_doc(path: pointer) -> Doc { let D = by_path(path) if (D != null) { return D } let text = read_file(path) @@ -1023,7 +1023,7 @@ program LudicLsp { return nd } - function scan_root(root: ptr) -> void { + function scan_root(root: pointer) -> void { if (root == null) { return } let listfile = "/tmp/ludic_lsp_scan.txt" run(concat3(concat3("find '", root, "' -name '*.ludic' -not -path '*/build/*' -not -path '*/node_modules/*' -not -path '*/.*' > "), listfile, " 2>/dev/null")) @@ -1096,7 +1096,7 @@ program LudicLsp { while i < len(rel) { if rel[i].is_unit == 1 and rel[i].is_md == 0 { return rel[i] }; i = i + 1 } return null } - function find_local(D: Doc, name: ptr, off: int) -> int { + function find_local(D: Doc, name: pointer, off: int) -> int { var best = 0 - 1 var i = 0 while i < len(D.syms) { @@ -1109,7 +1109,7 @@ program LudicLsp { return best } # returns sym index in g_owner (set), or -1 - function find_top(D: Doc, name: ptr) -> int { + function find_top(D: Doc, name: pointer) -> int { let rel = related(D) var i = 0 while i < len(rel) { @@ -1183,18 +1183,18 @@ program LudicLsp { } # ---- builtins / intrinsics (name -> signature) ---- - var g_builtins: []ptr - var g_bsigs: []ptr - function badd(name: ptr, sig: ptr) -> void { push(g_builtins, name); push(g_bsigs, sig) } - function is_builtin_name(name: ptr) -> bool { var i = 0; while i < len(g_builtins) { if (g_builtins[i] == name) { return true }; i = i + 1 }; return false } - function builtin_sig(name: ptr) -> ptr { var i = 0; while i < len(g_builtins) { if (g_builtins[i] == name) { return g_bsigs[i] }; i = i + 1 }; return null } + var g_builtins: []pointer + var g_bsigs: []pointer + function badd(name: pointer, sig: pointer) -> void { push(g_builtins, name); push(g_bsigs, sig) } + function is_builtin_name(name: pointer) -> bool { var i = 0; while i < len(g_builtins) { if (g_builtins[i] == name) { return true }; i = i + 1 }; return false } + function builtin_sig(name: pointer) -> pointer { var i = 0; while i < len(g_builtins) { if (g_builtins[i] == name) { return g_bsigs[i] }; i = i + 1 }; return null } # The namespaced standard-library surface: `Namespace.method`, mirroring the # compiler's emit_ns_call (selfhost/emit_expr.ludic). Screen/Random/Input/Map # methods resolve to the underlying bare builtin's signature; Math/Text/List # are pure fixed-point / string / slice ops with their own signatures. Returns # the signature label for signature help, or null if it is not a known method. - function ns_method_sig(ns: ptr, meth: ptr) -> ptr { + function ns_method_sig(ns: pointer, meth: pointer) -> pointer { if (ns == "Screen") { if (meth == "clear") { return builtin_sig("clear") } if (meth == "fill_rectangle") { return builtin_sig("fill_rect") } @@ -1366,14 +1366,14 @@ program LudicLsp { if (meth == "run") { return "System.run(command) -> int" } if (meth == "env") { return "System.env(name) -> string" } if (meth == "read_char") { return "System.read_char() -> int" } - if (meth == "file_open") { return "System.file_open(path, mode) -> ptr" } + if (meth == "file_open") { return "System.file_open(path, mode) -> pointer" } if (meth == "file_read") { return "System.file_read(file, buf, n) -> int" } if (meth == "file_write") { return "System.file_write(file, buf, n) -> int" } if (meth == "file_seek") { return "System.file_seek(file, offset, whence) -> int" } if (meth == "file_tell") { return "System.file_tell(file) -> int" } if (meth == "file_close") { return "System.file_close(file)" } - if (meth == "stdout") { return "System.stdout() -> ptr" } - if (meth == "stderr") { return "System.stderr() -> ptr" } + if (meth == "stdout") { return "System.stdout() -> pointer" } + if (meth == "stderr") { return "System.stderr() -> pointer" } } if (ns == "Save") { if (meth == "write") { return "Save.write()" } @@ -1386,7 +1386,7 @@ program LudicLsp { if (meth == "now") { return "Time.now() -> int" } } if (ns == "Memory") { - if (meth == "bytes") { return "Memory.bytes(n) -> ptr" } + if (meth == "bytes") { return "Memory.bytes(n) -> pointer" } if (meth == "words") { return "Memory.words(n) -> words" } if (meth == "copy") { return "Memory.copy(dst, src, n)" } if (meth == "fill") { return "Memory.fill(buf, value, n)" } @@ -1396,7 +1396,7 @@ program LudicLsp { return null } function init_builtins() -> void { - g_builtins = new []ptr; g_bsigs = new []ptr + g_builtins = new []pointer; g_bsigs = new []pointer badd("min", "min(a: int, b: int) -> int") badd("max", "max(a: int, b: int) -> int") badd("abs", "abs(a: int) -> int") @@ -1448,31 +1448,31 @@ program LudicLsp { badd("print", "print(x)") badd("string", "string(x) -> string") badd("quit", "quit()") - badd("bytes", "bytes(n: int) -> ptr") + badd("bytes", "bytes(n: int) -> pointer") badd("words", "words(n: int) -> words") - badd("resize", "resize(p: ptr, n: int) -> ptr") + badd("resize", "resize(p: pointer, n: int) -> pointer") badd("arg_count", "arg_count() -> int") badd("arg", "arg(i: int) -> string") - badd("file_stderr", "file_stderr() -> ptr") - badd("file_stdout", "file_stdout() -> ptr") - badd("free", "free(p: ptr)") - badd("fill", "fill(p: ptr, byte: int, n: int)") - badd("offset", "offset(p: ptr, off: int) -> ptr") + badd("file_stderr", "file_stderr() -> pointer") + badd("file_stdout", "file_stdout() -> pointer") + badd("free", "free(p: pointer)") + badd("fill", "fill(p: pointer, byte: int, n: int)") + badd("offset", "offset(p: pointer, off: int) -> pointer") badd("as_fixed", "as_fixed(i: int) -> fixed") badd("as_int", "as_int(f: fixed) -> int") - badd("file_open", "file_open(path: string, mode: string) -> ptr") - badd("file_read", "file_read(f: ptr, buf: ptr, n: int) -> int") - badd("file_write", "file_write(f: ptr, buf: ptr, n: int) -> int") - badd("file_seek", "file_seek(f: ptr, off: int, whence: int) -> int") - badd("file_tell", "file_tell(f: ptr) -> int") - badd("file_close", "file_close(f: ptr)") + badd("file_open", "file_open(path: string, mode: string) -> pointer") + badd("file_read", "file_read(f: pointer, buf: pointer, n: int) -> int") + badd("file_write", "file_write(f: pointer, buf: pointer, n: int) -> int") + badd("file_seek", "file_seek(f: pointer, off: int, whence: int) -> int") + badd("file_tell", "file_tell(f: pointer) -> int") + badd("file_close", "file_close(f: pointer)") badd("read_char", "read_char() -> int") badd("exit", "exit(code: int)") badd("is_windowed", "is_windowed() -> bool") badd("game_title", "game_title() -> string") badd("win_open", "win_open(title: string, w: int, h: int, scale: int)") badd("win_poll", "win_poll() -> int") - badd("win_present", "win_present(px: ptr, w: int, h: int)") + badd("win_present", "win_present(px: pointer, w: int, h: int)") badd("win_running", "win_running() -> bool") badd("win_close", "win_close()") } @@ -1579,13 +1579,13 @@ program LudicLsp { const JSTR: int = 3 const JARR: int = 4 const JOBJ: int = 5 - property JVal { t: int = 0, num: int = 0, b: int = 0, s: ptr = null, kids: []JVal, keys: []ptr } - function jval(t: int) -> JVal { let v = new JVal; v.t = t; v.kids = new []JVal; v.keys = new []ptr; return v } + property JVal { t: int = 0, num: int = 0, b: int = 0, s: pointer = null, kids: []JVal, keys: []pointer } + function jval(t: int) -> JVal { let v = new JVal; v.t = t; v.kids = new []JVal; v.keys = new []pointer; return v } - var jsrc: ptr = null + var jsrc: pointer = null var jp: int = 0 function jskip() -> void { while jsrc[jp] == 32 or jsrc[jp] == 9 or jsrc[jp] == 10 or jsrc[jp] == 13 { jp = jp + 1 } } - function jhex4(s: ptr, at: int) -> int { + function jhex4(s: pointer, at: int) -> int { var v = 0; var i = 0 while i < 4 { let h = hexval(s[at + i]); if h < 0 { return v }; v = v * 16 + h; i = i + 1 } return v @@ -1596,7 +1596,7 @@ program LudicLsp { else { if cp < 65536 { buf_putc(o, 224 | (cp >> 12)); buf_putc(o, 128 | ((cp >> 6) & 63)); buf_putc(o, 128 | (cp & 63)) } else { buf_putc(o, 240 | (cp >> 18)); buf_putc(o, 128 | ((cp >> 12) & 63)); buf_putc(o, 128 | ((cp >> 6) & 63)); buf_putc(o, 128 | (cp & 63)) } } } } - function jparse_string() -> ptr { + function jparse_string() -> pointer { jp = jp + 1 # skip opening quote let o = buf_new() while jsrc[jp] != 0 and jsrc[jp] != 34 { @@ -1671,7 +1671,7 @@ program LudicLsp { jp = jp + 1 return jval(JNULL) } - function jget(v: JVal, key: ptr) -> JVal { + function jget(v: JVal, key: pointer) -> JVal { if (v == null) { return null } if v.t != JOBJ { return null } var i = 0 @@ -1680,9 +1680,9 @@ program LudicLsp { } function jat(v: JVal, i: int) -> JVal { if (v == null) { return null }; if i < 0 or i >= len(v.kids) { return null }; return v.kids[i] } function jlen(v: JVal) -> int { if (v == null) { return 0 }; return len(v.kids) } - function jstr(v: JVal, def: ptr) -> ptr { if (v != null) and v.t == JSTR and (v.s != null) { return v.s }; return def } + function jstr(v: JVal, def: pointer) -> pointer { if (v != null) and v.t == JSTR and (v.s != null) { return v.s }; return def } function jint(v: JVal, def: int) -> int { if (v != null) and v.t == JNUM { return v.num }; return def } - function jpath(v: JVal, path: ptr) -> JVal { + function jpath(v: JVal, path: pointer) -> JVal { var cur = v let n = cstr_len(path) var start = 0; var i = 0 @@ -1741,16 +1741,16 @@ program LudicLsp { } return 1 } - function f_is_clause(w: ptr) -> bool { + function f_is_clause(w: pointer) -> bool { return (w == "phase") or (w == "query") or (w == "reads") or (w == "writes") or (w == "needs") or (w == "uses") or (w == "requires") or (w == "ensures") or (w == "invariant") or (w == "effects") } - function make_text_doc(text: ptr) -> Doc { + function make_text_doc(text: pointer) -> Doc { let F = new Doc F.raw = text; F.text = text; F.src = text; F.is_md = 0 lex_doc(F) return F } - function format_doc(F: Doc, iw: int) -> ptr { + function format_doc(F: Doc, iw: int) -> pointer { let o = buf_new() let stack = words(600) let hang = words(600) @@ -1855,7 +1855,7 @@ program LudicLsp { var mf_flen: int = 0 var mf_info: int = 0 var mf_marker: int = 0 - function mf_fence_at(s: ptr, i: int) -> bool { + function mf_fence_at(s: pointer, i: int) -> bool { var j = i; while s[j] == 32 { j = j + 1 } let m = s[j] if m != 96 and m != 126 { return false } @@ -1864,8 +1864,8 @@ program LudicLsp { mf_flen = n; mf_info = j; mf_marker = m return true } - function f_line_end(s: ptr, i: int) -> int { var e = i; while s[e] != 0 and s[e] != 10 { e = e + 1 }; return e } - function format_md(s: ptr, iw: int) -> ptr { + function f_line_end(s: pointer, i: int) -> int { var e = i; while s[e] != 0 and s[e] != 10 { e = e + 1 }; return e } + function format_md(s: pointer, iw: int) -> pointer { let o = buf_new() var i = 0 while s[i] != 0 { @@ -1925,14 +1925,14 @@ program LudicLsp { } return buf_str(o) } - function skip_ws2(s: ptr, at: int) -> int { var a = at; while s[a] == 32 or s[a] == 9 { a = a + 1 }; return a } + function skip_ws2(s: pointer, at: int) -> int { var a = at; while s[a] == 32 or s[a] == 9 { a = a + 1 }; return a } # ============================================================================ # framing + output # ============================================================================ - extern function fflush(f: ptr) -> int = "fflush" + extern function fflush(f: pointer) -> int = "fflush" - function jstr_out(o: Buf, z: ptr) -> void { + function jstr_out(o: Buf, z: pointer) -> void { buf_putc(o, 34) if (z == null) { buf_putc(o, 34); return } var i = 0 @@ -1950,7 +1950,7 @@ program LudicLsp { buf_putc(o, 34) } - function send_raw(body: ptr) -> void { + function send_raw(body: pointer) -> void { let hdr = buf_new() buf_puts(hdr, "Content-Length: "); buf_puti(hdr, cstr_len(body)); buf_putc(hdr, 13); buf_putc(hdr, 10); buf_putc(hdr, 13); buf_putc(hdr, 10) let hs = buf_str(hdr) @@ -1959,7 +1959,7 @@ program LudicLsp { file_write(out, body, cstr_len(body)) let z = fflush(out) } - function send_result(idv: JVal, result: ptr) -> void { + function send_result(idv: JVal, result: pointer) -> void { let o = buf_new() buf_puts(o, "{\"jsonrpc\":\"2.0\",\"id\":") if (idv == null) { buf_puts(o, "null") } @@ -1969,19 +1969,19 @@ program LudicLsp { buf_putc(o, 125) send_raw(buf_str(o)) } - function send_notify(method: ptr, params: ptr) -> void { + function send_notify(method: pointer, params: pointer) -> void { let o = buf_new() buf_puts(o, "{\"jsonrpc\":\"2.0\",\"method\":"); jstr_out(o, method); buf_puts(o, ",\"params\":"); buf_puts(o, params); buf_putc(o, 125) send_raw(buf_str(o)) } function lower(c: int) -> int { if c >= 65 and c <= 90 { return c + 32 }; return c } - function starts_with_ci(s: ptr, pre: ptr) -> bool { + function starts_with_ci(s: pointer, pre: pointer) -> bool { var i = 0 while pre[i] != 0 { if s[i] == 0 or lower(s[i]) != lower(pre[i]) { return false }; i = i + 1 } return true } - function read_message() -> ptr { + function read_message() -> pointer { var length = 0 - 1 let line = buf_new() while true { @@ -2015,12 +2015,12 @@ program LudicLsp { if (D != null) { return D } return ensure_doc(uri_to_path(uri)) } - function off_of(msg: JVal, D: Doc, base: ptr) -> int { + function off_of(msg: JVal, D: Doc, base: pointer) -> int { let line = jint(jpath(msg, concat3(base, ".line", "")), 0) let ch = jint(jpath(msg, concat3(base, ".character", "")), 0) return offset_of(D, line, ch) } - function basename(p: ptr) -> ptr { var last = 0 - 1; var i = 0; while p[i] != 0 { if p[i] == 47 { last = i }; i = i + 1 }; return p[last + 1..i] } + function basename(p: pointer) -> pointer { var last = 0 - 1; var i = 0; while p[i] != 0 { if p[i] == 47 { last = i }; i = i + 1 }; return p[last + 1..i] } # ---- LSP symbol kinds & completion kinds ---- function lsp_symbol_kind(k: int) -> int { @@ -2055,7 +2055,7 @@ program LudicLsp { # ---- diagnostics (structural) ---- function diag_structural(D: Doc, o: Buf) -> void { - let ds_s = new []int; let ds_e = new []int; let ds_m = new []ptr + let ds_s = new []int; let ds_e = new []int; let ds_m = new []pointer let stack = words(1200); var top = 0 var i = 0; let N = ntok(D) while i < N { @@ -2116,7 +2116,7 @@ program LudicLsp { } # ---- hover ---- - function hover_md(o: Buf, code: ptr, docstr: ptr) -> void { + function hover_md(o: Buf, code: pointer, docstr: pointer) -> void { let m = buf_new() buf_puts(m, "```ludic\n"); buf_puts(m, code); buf_puts(m, "\n```") if (docstr != null) and (docstr[0] != 0) { buf_puts(m, "\n\n"); buf_puts(m, docstr) } @@ -2250,7 +2250,7 @@ program LudicLsp { # ---- completion ---- var g_first: int = 1 - function comp_item(o: Buf, label: ptr, kind: int, detail: ptr) -> void { + function comp_item(o: Buf, label: pointer, kind: int, detail: pointer) -> void { if g_first == 0 { buf_putc(o, 44) } g_first = 0 buf_puts(o, "{\"label\":"); jstr_out(o, label); buf_puts(o, ",\"kind\":"); buf_puti(o, kind) @@ -2287,7 +2287,7 @@ program LudicLsp { } function comp_types(o: Buf) -> void { comp_item(o, "int", 14, "built-in type"); comp_item(o, "long", 14, "built-in type"); comp_item(o, "fixed", 14, "built-in type"); comp_item(o, "bool", 14, "built-in type") - comp_item(o, "entity", 14, "built-in type"); comp_item(o, "string", 14, "built-in type"); comp_item(o, "ptr", 14, "built-in type"); comp_item(o, "void", 14, "built-in type") + comp_item(o, "entity", 14, "built-in type"); comp_item(o, "string", 14, "built-in type"); comp_item(o, "pointer", 14, "built-in type"); comp_item(o, "void", 14, "built-in type") } function comp_builtins(o: Buf) -> void { var i = 0; while i < len(g_builtins) { comp_item(o, g_builtins[i], 3, g_bsigs[i]); i = i + 1 } } function on_completion(msg: JVal, id: JVal) -> void { @@ -2392,7 +2392,7 @@ program LudicLsp { } if callee < 0 or D.tk_kind[callee] != LT_ID { send_result(id, "null"); return } let name = ttext(D, callee) - var sig: ptr = null + var sig: pointer = null # a namespaced call `Namespace.method(` resolves through the ns surface first let dot = prev_sig(D, callee) if dot >= 0 and tis(D, dot, ".") { @@ -2487,7 +2487,7 @@ program LudicLsp { } buf_putc(o, 93); send_result(id, buf_str(o)) } - function contains_ci(hay: ptr, needle: ptr) -> bool { + function contains_ci(hay: pointer, needle: pointer) -> bool { let hn = cstr_len(hay); let nn = cstr_len(needle) if nn == 0 { return true } var i = 0 @@ -2548,7 +2548,7 @@ program LudicLsp { if (disk != null) { set_text(D, disk); reindex(D) } } - function caps() -> ptr { + function caps() -> pointer { let o = buf_new() buf_puts(o, "{\"capabilities\":{") buf_puts(o, "\"positionEncoding\":\"utf-16\"") diff --git a/tools/ludic-tools/ludic_syntax.h b/tools/ludic-tools/ludic_syntax.h index 1334e047..aaf0bf3c 100644 --- a/tools/ludic-tools/ludic_syntax.h +++ b/tools/ludic-tools/ludic_syntax.h @@ -71,7 +71,7 @@ static const char* LUDIC_KW_STMT[] = { "and","or","not","break","continue","new","emit","cancel", 0 }; static const char* LUDIC_TYPES[] = { - "int","long","fixed","bool","entity","string","ptr","byte","words","fixeds","ptrs","void", 0 + "int","long","fixed","bool","entity","string","pointer","byte","words","fixeds","pointers","void", 0 }; static const char* LUDIC_PHASES[] = { "Start","Input","FixedUpdate","Update","LateUpdate","Render", 0 diff --git a/tools/x/build.ludic b/tools/x/build.ludic index 11113b4f..384a7ac0 100644 --- a/tools/x/build.ludic +++ b/tools/x/build.ludic @@ -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 diff --git a/tools/x/main.ludic b/tools/x/main.ludic index 68f77efc..8fa95c22 100644 --- a/tools/x/main.ludic +++ b/tools/x/main.ludic @@ -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 } diff --git a/tools/x/prelude.ludic b/tools/x/prelude.ludic index 002932f3..d345a3a0 100644 --- a/tools/x/prelude.ludic +++ b/tools/x/prelude.ludic @@ -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}]`) } } diff --git a/tools/x/selfhost.ludic b/tools/x/selfhost.ludic index 982ddfea..8ba05bee 100644 --- a/tools/x/selfhost.ludic +++ b/tools/x/selfhost.ludic @@ -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 -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 -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")) diff --git a/tools/x/selfhost_test.ludic b/tools/x/selfhost_test.ludic index 1c0dc49d..5f4a2f01 100644 --- a/tools/x/selfhost_test.ludic +++ b/tools/x/selfhost_test.ludic @@ -3,7 +3,7 @@ # fixpoint). Replaces selfhost/test.sh. # compile selfhost/tests/.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/.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`) } diff --git a/tools/x/test.ludic b/tools/x/test.ludic index 2c52c2d7..f886bc03 100644 --- a/tools/x/test.ludic +++ b/tools/x/test.ludic @@ -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`) { diff --git a/tools/x/tools.ludic b/tools/x/tools.ludic index 9e23218e..e39bfeb5 100644 --- a/tools/x/tools.ludic +++ b/tools/x/tools.ludic @@ -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}`)