refactor(lang): rename the fn keyword to function
Expand the function-declaration keyword to the full word across the whole
language and toolchain:
fn name(...) -> T { ... } -> function name(...) -> T { ... }
Done as a self-hosting migration: teach the parser both spellings, reseed,
rewrite every .ludic definition to `function`, then drop `fn`. The compiler
now rejects `fn`. Touches the parser, all selfhost/tools/runtime/example/test
sources, the grammars (TextMate shared+vscode, ludic_syntax.h, JetBrains
LudicTokens.kt), the LSP and formatter, the Python doc/vocab tools
(check-impl, check-docs, validate, palette, test-lsp), and the docs
(fences, prose, kw-fn -> kw-function).
Reseeded; C-free bootstrap fixpoint holds. All suites green (45 regression,
24 self-host, 29 tool); the docs site generates and check.py passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2f19c8d8e2
commit
4c48077d68
86 changed files with 793 additions and 793 deletions
|
|
@ -4,18 +4,18 @@ name: @export
|
|||
category: annotations
|
||||
kind: annotation
|
||||
tokens: @export
|
||||
sig: @export fn name(…) -> R
|
||||
sig: @export function name(…) -> R
|
||||
tip: Expose a function as a native symbol so a host can call it.
|
||||
order: 3
|
||||
---
|
||||
|
||||
<code>@export</code> makes a <code>fn</code> visible outside the module as a plain native symbol, so a host program or another linked object can call it by name. Without it, functions are internal to the compiled unit; with it, the emitted symbol is externally linkable, which is how Ludic hands entry points to a runtime seam or a foreign caller. It is the outbound counterpart to <code>extern fn</code>, which pulls a foreign symbol in. Keep exported signatures to POD scalars and pointers, since they cross a native ABI boundary where Ludic's richer types do not apply.
|
||||
<code>@export</code> makes a <code>function</code> visible outside the module as a plain native symbol, so a host program or another linked object can call it by name. Without it, functions are internal to the compiled unit; with it, the emitted symbol is externally linkable, which is how Ludic hands entry points to a runtime seam or a foreign caller. It is the outbound counterpart to <code>extern function</code>, which pulls a foreign symbol in. Keep exported signatures to POD scalars and pointers, since they cross a native ABI boundary where Ludic's richer types do not apply.
|
||||
|
||||
```ludic
|
||||
program ScoreModule {
|
||||
var running_total: int = 0
|
||||
|
||||
@export fn add_points(amount: int) -> int { # callable from a native host
|
||||
@export function add_points(amount: int) -> int { # callable from a native host
|
||||
running_total = running_total + amount
|
||||
return running_total
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ name: extern
|
|||
category: structure
|
||||
kind: keyword
|
||||
tokens: extern
|
||||
sig: extern fn name(a: T) -> R = "symbol"
|
||||
sig: extern function name(a: T) -> R = "symbol"
|
||||
tip: Bind a name to an external native symbol — the seam for platform and library calls.
|
||||
order: 12
|
||||
---
|
||||
|
||||
An <code>extern fn</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`, `ptr`, …).
|
||||
|
||||
Parameters:
|
||||
- `a` — a typed argument passed straight through to the foreign symbol
|
||||
|
||||
```ludic
|
||||
program Physics {
|
||||
extern fn c_hypot(a: fixed, b: fixed) -> fixed = "hypot_fx"
|
||||
extern function c_hypot(a: fixed, b: fixed) -> fixed = "hypot_fx"
|
||||
|
||||
property Velocity { delta_x: int = 0, delta_y: int = 0 }
|
||||
model Projectile { Velocity }
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
id: kw-fn
|
||||
name: fn
|
||||
category: structure
|
||||
kind: keyword
|
||||
tokens: fn
|
||||
sig: fn name(a: T, b: T) -> R { … }
|
||||
tip: A function — reusable logic called positionally or with named arguments.
|
||||
order: 8
|
||||
---
|
||||
|
||||
A <code>fn</code> declares a function: a reusable block of logic with typed parameters and a return type, written `-> R` (use `-> void` for one that returns nothing). Call it positionally, `heal(2, 10)`, or with named arguments, `heal(amount: 2, maximum: 10)`, which reads more clearly at the call site and is the house style. Functions live at program scope alongside handlers and may be called from any handler; they can `spawn`, run queries, and read program-scope state. Use them to factor out logic shared by several handlers so each handler stays short.
|
||||
|
||||
Parameters:
|
||||
- `a`, `b` — the typed inputs; pass them positionally or by name at the call site
|
||||
|
||||
```ludic
|
||||
program Healer {
|
||||
property Health { current: int = 100, maximum: int = 100 }
|
||||
model Player { Health }
|
||||
|
||||
fn heal(amount: int, maximum: int) -> int {
|
||||
let restored = amount * 2
|
||||
if restored > maximum { return maximum }
|
||||
return restored
|
||||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
spawn Hero { Health { current: 10, maximum: 100 } }
|
||||
}
|
||||
|
||||
handler Recover phase Update {
|
||||
for (health) in query [Health, {Player}] {
|
||||
health.current = heal(amount: health.current, maximum: health.maximum)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
38
docs/language/structure/kw-function.md
Normal file
38
docs/language/structure/kw-function.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
id: kw-function
|
||||
name: function
|
||||
category: structure
|
||||
kind: keyword
|
||||
tokens: function
|
||||
sig: function name(a: T, b: T) -> R { … }
|
||||
tip: A function — reusable logic called positionally or with named arguments.
|
||||
order: 8
|
||||
---
|
||||
|
||||
A <code>function</code> declares a function: a reusable block of logic with typed parameters and a return type, written `-> R` (use `-> void` for one that returns nothing). Call it positionally, `heal(2, 10)`, or with named arguments, `heal(amount: 2, maximum: 10)`, which reads more clearly at the call site and is the house style. Functions live at program scope alongside handlers and may be called from any handler; they can `spawn`, run queries, and read program-scope state. Use them to factor out logic shared by several handlers so each handler stays short.
|
||||
|
||||
Parameters:
|
||||
- `a`, `b` — the typed inputs; pass them positionally or by name at the call site
|
||||
|
||||
```ludic
|
||||
program Healer {
|
||||
property Health { current: int = 100, maximum: int = 100 }
|
||||
model Player { Health }
|
||||
|
||||
function heal(amount: int, maximum: int) -> int {
|
||||
let restored = amount * 2
|
||||
if restored > maximum { return maximum }
|
||||
return restored
|
||||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
spawn Hero { Health { current: 10, maximum: 100 } }
|
||||
}
|
||||
|
||||
handler Recover phase Update {
|
||||
for (health) in query [Health, {Player}] {
|
||||
health.current = heal(amount: health.current, maximum: health.maximum)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -16,7 +16,7 @@ program Clamp {
|
|||
property Health { current: int = 100, maximum: int = 100 }
|
||||
model Player { Health }
|
||||
|
||||
fn clamp_current(value: int, maximum: int) -> int {
|
||||
function clamp_current(value: int, maximum: int) -> int {
|
||||
if value < 0 { return 0 }
|
||||
if value > maximum { return maximum }
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ 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 fn` passes an opaque C handle across the ABI. Test one for emptiness against the `null` literal.
|
||||
`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)
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ tip: The absence of a value — the return type of a function that returns nothi
|
|||
order: 50
|
||||
---
|
||||
|
||||
`void` is the absence of a value. It appears as the return type of a function that runs for its effect and hands nothing back — `fn reset_score() -> void { … }`. Such a function is called as a statement, not used in an expression, and a bare `return` (with no value) leaves it early. Use `void` whenever a helper mutates program state, draws, or spawns rather than computing a result to return.
|
||||
`void` is the absence of a value. It appears as the return type of a function that runs for its effect and hands nothing back — `function reset_score() -> void { … }`. Such a function is called as a statement, not used in an expression, and a bare `return` (with no value) leaves it early. Use `void` whenever a helper mutates program state, draws, or spawns rather than computing a result to return.
|
||||
|
||||
```ludic
|
||||
fn reset_score() -> void {
|
||||
function reset_score() -> void {
|
||||
score = 0
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue