refactor(lang): rename the ptr/ptrs types to pointer/pointers
Expand the abbreviated pointer types to full words on the language surface: ptr -> pointer (a raw address / FFI handle) ptrs -> pointers (a buffer of pointers) The Ludic type name is distinct from LLVM's own `ptr` spelling: llty() maps `pointer`/`pointers` to LLVM `ptr`, and the emitted IR keeps `ptr`, so only the Ludic-level surface changes. Rewrites type annotations across all sources, the 8 hardcoded pointer type-tags, the `pointers`-buffer indexing in emit_addr, the grammars/LSP/JetBrains tokens, and the docs (type-ptr -> type-pointer, type-ptrs -> type-pointers). int/bool keep their conventional short spelling (like Math). Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b7745a4600
commit
effb3f637f
76 changed files with 516 additions and 516 deletions
|
|
@ -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: <code>@Sync</code> says <b>what</b> replicates and <code>@Owned</code> says <b>who</b> 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 <code>@Sync</code>, either on the field or via <code>@Sync property P</code> which marks every field of <code>P</code>) <b>and</b> participating (the model marks the component <code>@Sync</code>). So the same property can replicate in one model and not another, and there is no <code>@NoSync</code> because the surface is purely additive. From these marks the compiler generates the per-model <code>serialize</code>/<code>apply</code> codecs; <code>@Sync</code> on a non-POD-scalar field (like a <code>ptr</code>) is a compile error, since a machine-local pointer cannot cross the wire. <code>@Owned</code> adds the owner slot the ownership builtins and <code>@Predicted</code> read. See the dedicated <code>@Owned</code> page for ownership details.
|
||||
These are the two declarative switches at the top of Ludic's networking: <code>@Sync</code> says <b>what</b> replicates and <code>@Owned</code> says <b>who</b> 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 <code>@Sync</code>, either on the field or via <code>@Sync property P</code> which marks every field of <code>P</code>) <b>and</b> participating (the model marks the component <code>@Sync</code>). So the same property can replicate in one model and not another, and there is no <code>@NoSync</code> because the surface is purely additive. From these marks the compiler generates the per-model <code>serialize</code>/<code>apply</code> codecs; <code>@Sync</code> on a non-POD-scalar field (like a <code>pointer</code>) is a compile error, since a machine-local pointer cannot cross the wire. <code>@Owned</code> adds the owner slot the ownership builtins and <code>@Predicted</code> read. See the dedicated <code>@Owned</code> page for ownership details.
|
||||
|
||||
```ludic
|
||||
program SyncedWorld {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ tip: Bind a name to an external native symbol — the seam for platform and libr
|
|||
order: 12
|
||||
---
|
||||
|
||||
An <code>extern function</code> 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 <code>extern function</code> 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
18
docs/language/types/type-pointer.md
Normal file
18
docs/language/types/type-pointer.md
Normal file
|
|
@ -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 }
|
||||
```
|
||||
25
docs/language/types/type-pointers.md
Normal file
25
docs/language/types/type-pointers.md
Normal file
|
|
@ -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 <code>pointers</code> is a raw buffer whose elements are pointers: index it with <code>buffer[i]</code> to read or write a <code>pointer</code>, with no bounds checking. Allocate the storage with <code>words(n)</code> (a pointer fits in a slot) and type the binding as <code>pointers</code> 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 <code>new</code>, a free list, a bucket array — for when you want manual control instead of a growable <code>[]T</code> 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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 }
|
||||
```
|
||||
|
|
@ -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 <code>ptrs</code> is a raw buffer whose elements are pointers: index it with <code>buffer[i]</code> to read or write a <code>ptr</code>, with no bounds checking. Allocate the storage with <code>words(n)</code> (a pointer fits in a slot) and type the binding as <code>ptrs</code> 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 <code>new</code>, a free list, a bucket array — for when you want manual control instead of a growable <code>[]T</code> 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue