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:
Orkun ÇAKILKAYA 2026-08-30 01:43:22 +03:00
parent 2f19c8d8e2
commit 4c48077d68
86 changed files with 793 additions and 793 deletions

View file

@ -29,11 +29,11 @@ var rt_alive: int = 1 # platform still running?
# 5x7 glyphs for ASCII 32..90, 7 rows per glyph, each row a 5-bit mask stored
# biased by '0' so the whole font is one printable string literal.
fn rt_font() -> str {
function rt_font() -> str {
return "00000004444404000000000000000000000IJ4:FC000000000000000000000000000000E>O>E0044O4400000448000O000000004012448@@>ACEIA>4<4444>>A168@ON11>11N26:BO22O@N11A>>@@NAA>O124888>AA>AA>>AA?11>04004000000000024842000O0O000842480>A164040000000>AAOAAANAANAAN>A@@@A>LBAAABLO@@L@@OO@@L@@@>A@GAA>AAAOAAA>44444>7222BB<ABDHDBA@@@@@@OAKEEAAAAIEECAA>AAAAA>NAAN@@@>AAAEB=NAANDBA>A@>1A>O444444AAAAAA>AAAAA:4AAAEEKAAA:4:AAAA:4444O1248@O"
}
fn rt_init() -> void {
function rt_init() -> void {
rt_fb = words(320 * 240)
rt_regs = words(64)
fill(rt_regs, 0, 64 * 4)
@ -50,7 +50,7 @@ fn rt_init() -> void {
}
}
fn rt_shutdown() -> void {
function rt_shutdown() -> void {
if is_windowed() {
win_close()
return
@ -59,17 +59,17 @@ fn rt_shutdown() -> void {
}
# ---- framebuffer ----------------------------------------------------------
fn rt_screen_w() -> int { return rt_fbw }
fn rt_screen_h() -> int { return rt_fbh }
function rt_screen_w() -> int { return rt_fbw }
function rt_screen_h() -> int { return rt_fbh }
fn rt_clear(c: int) -> void {
function rt_clear(c: int) -> void {
let n = rt_fbw * rt_fbh
for i in 0 .. n {
rt_fb[i] = c
}
}
fn rt_put_px(x: int, y: int, c: int) -> void {
function rt_put_px(x: int, y: int, c: int) -> void {
if x < 0 { return }
if y < 0 { return }
if x >= rt_fbw { return }
@ -77,7 +77,7 @@ fn rt_put_px(x: int, y: int, c: int) -> void {
rt_fb[y * rt_fbw + x] = c
}
fn rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void {
function rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void {
let x0 = max(0, x)
let y0 = max(0, y)
let x1 = min(rt_fbw, x + w)
@ -94,7 +94,7 @@ fn rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void {
}
}
fn rt_frame_rect(x: int, y: int, w: int, h: int, c: int) -> void {
function rt_frame_rect(x: int, y: int, w: int, h: int, c: int) -> void {
rt_fill_rect(x, y, w, 1, c)
rt_fill_rect(x, y + h - 1, w, 1, c)
rt_fill_rect(x, y, 1, h, c)
@ -102,7 +102,7 @@ fn rt_frame_rect(x: int, y: int, w: int, h: int, c: int) -> void {
}
# A straight line by Bresenham's algorithm — integer only, any direction.
fn rt_line(x0: int, y0: int, x1: int, y1: int, c: int) -> void {
function rt_line(x0: int, y0: int, x1: int, y1: int, c: int) -> void {
var x = x0; var y = y0
let dx = abs(x1 - x0); let dy = 0 - abs(y1 - y0)
var sx = 0 - 1; if x0 < x1 { sx = 1 }
@ -118,7 +118,7 @@ fn rt_line(x0: int, y0: int, x1: int, y1: int, c: int) -> void {
}
# A circle outline by the midpoint algorithm (eight-way symmetry).
fn rt_circle(cx: int, cy: int, r: int, c: int) -> void {
function rt_circle(cx: int, cy: int, r: int, c: int) -> void {
if r < 0 { return }
var x = r; var y = 0; var err = 1 - r
while x >= y {
@ -133,7 +133,7 @@ fn rt_circle(cx: int, cy: int, r: int, c: int) -> void {
}
# A filled disc — one horizontal span per row, width from the circle equation.
fn rt_fill_circle(cx: int, cy: int, r: int, c: int) -> void {
function rt_fill_circle(cx: int, cy: int, r: int, c: int) -> void {
if r < 0 { return }
let r2 = r * r
var dy = 0 - r
@ -146,14 +146,14 @@ fn rt_fill_circle(cx: int, cy: int, r: int, c: int) -> void {
}
# A triangle outline — three lines.
fn rt_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, c: int) -> void {
function rt_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, c: int) -> void {
rt_line(x0, y0, x1, y1, c)
rt_line(x1, y1, x2, y2, c)
rt_line(x2, y2, x0, y0, c)
}
# A filled triangle — bounding-box scan with an edge-sign inside test.
fn rt_fill_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, c: int) -> void {
function rt_fill_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, c: int) -> void {
let minx = min(x0, min(x1, x2)); let maxx = max(x0, max(x1, x2))
let miny = min(y0, min(y1, y2)); let maxy = max(y0, max(y1, y2))
var py = miny
@ -174,14 +174,14 @@ fn rt_fill_triangle(x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, c: int
# Windowed: hand the framebuffer to the platform layer, which blits it into
# the view. Headless: nothing to do until shutdown writes the last frame out.
fn rt_present() -> void {
function rt_present() -> void {
if is_windowed() {
win_present(rt_fb, rt_fbw, rt_fbh)
}
}
# ---- text -----------------------------------------------------------------
fn rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
function rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
var c = ch
if c >= 97 {
if c <= 122 { c = c - 32 }
@ -203,7 +203,7 @@ fn rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
}
}
fn rt_text(x: int, y: int, s: str, colour: int, sc: int) -> void {
function rt_text(x: int, y: int, s: str, colour: int, sc: int) -> void {
var i = 0
var cx = x
var ch = s[0]
@ -215,7 +215,7 @@ fn rt_text(x: int, y: int, s: str, colour: int, sc: int) -> void {
}
}
fn rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void {
function rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void {
if n == 0 {
rt_glyph(x, y, 48, colour, sc)
return
@ -246,20 +246,20 @@ fn rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void {
}
# ---- registers ------------------------------------------------------------
fn rt_reg(i: int) -> int {
function rt_reg(i: int) -> int {
if i < 0 { return 0 }
if i >= 64 { return 0 }
return rt_regs[i]
}
fn rt_set_reg(i: int, v: int) -> void {
function rt_set_reg(i: int, v: int) -> void {
if i < 0 { return }
if i >= 64 { return }
rt_regs[i] = v
}
# ---- rng (xorshift32) -----------------------------------------------------
fn rt_seed(s: int) -> void {
function rt_seed(s: int) -> void {
if s == 0 {
rt_rng = 305419896
return
@ -269,7 +269,7 @@ fn rt_seed(s: int) -> void {
# xorshift32 (Marsaglia). Runs on the raw 32-bit pattern, so the sign bit is
# masked off only when a caller asks for a number.
fn rt_next_rand() -> int {
function rt_next_rand() -> int {
var x = rt_rng
x = (x ^ (x << 13))
x = (x ^ (x >> 17))
@ -278,35 +278,35 @@ fn rt_next_rand() -> int {
return (x & 2147483647)
}
fn rt_rng_range(lo: int, hi: int) -> int {
function rt_rng_range(lo: int, hi: int) -> int {
if hi <= lo { return lo }
return lo + rt_next_rand() % (hi - lo + 1)
}
fn rt_rng_chance(pct: int) -> bool {
function rt_rng_chance(pct: int) -> bool {
return rt_next_rand() % 100 < pct
}
# a deterministic fixed-point value in [0, 1) — the raw 0..65535 is exactly the
# Q16.16 fraction (fixed and int share the i32 representation).
fn rt_rng_value() -> fixed {
function rt_rng_value() -> fixed {
return rt_rng_range(0, 65535)
}
# a deterministic integer in [0, max) — 0 when max <= 0
fn rt_rng_int(max: int) -> int {
function rt_rng_int(max: int) -> int {
if max <= 0 { return 0 }
return rt_rng_range(0, max - 1)
}
# a deterministic +1 or -1
fn rt_rng_sign() -> int {
function rt_rng_sign() -> int {
if rt_rng_chance(50) { return 1 }
return 0 - 1
}
# ---- platform: input ------------------------------------------------------
fn rt_poll() -> int {
function rt_poll() -> int {
if is_windowed() {
return win_poll()
}
@ -321,7 +321,7 @@ fn rt_poll() -> int {
return c
}
fn rt_running() -> bool {
function rt_running() -> bool {
if is_windowed() {
return win_running()
}
@ -329,7 +329,7 @@ fn rt_running() -> bool {
}
# ---- writing the frame out ------------------------------------------------
fn rt_put_str(buf: ptr, at: int, s: str) -> int {
function rt_put_str(buf: ptr, at: int, s: str) -> int {
var i = 0
var n = at
var ch = s[0]
@ -342,7 +342,7 @@ fn rt_put_str(buf: ptr, at: int, s: str) -> int {
return n
}
fn rt_put_int(buf: ptr, at: int, v: int) -> int {
function rt_put_int(buf: ptr, at: int, v: int) -> int {
if v == 0 {
buf[at] = 48
return at + 1
@ -367,7 +367,7 @@ fn rt_put_int(buf: ptr, at: int, v: int) -> int {
return n
}
fn rt_dump_ppm(path: str) -> void {
function rt_dump_ppm(path: str) -> void {
let f = file_open(path, "wb")
if (f == null) { return }
@ -406,13 +406,13 @@ var rt_map: ptr = null
var rt_mapw: int = 0
var rt_maph: int = 0
fn rt_map_size(w: int, h: int) -> void {
function rt_map_size(w: int, h: int) -> void {
rt_mapw = clamp(w, 0, 96)
rt_maph = clamp(h, 0, 64)
fill(rt_map, 32, 96 * 64)
}
fn rt_map_row(y: int, s: str) -> void {
function rt_map_row(y: int, s: str) -> void {
if y < 0 { return }
if y >= 64 { return }
var x = 0
@ -425,7 +425,7 @@ fn rt_map_row(y: int, s: str) -> void {
}
}
fn rt_tile(x: int, y: int) -> int {
function rt_tile(x: int, y: int) -> int {
if x < 0 { return 35 }
if y < 0 { return 35 }
if x >= rt_mapw { return 35 }
@ -438,7 +438,7 @@ fn rt_tile(x: int, y: int) -> int {
# so it survives whatever the caller does with the original.
var rt_statusbuf: ptr = null
fn rt_status(s: str) -> void {
function rt_status(s: str) -> void {
var i = 0
var ch = s[0]
while ch != 0 {
@ -452,7 +452,7 @@ fn rt_status(s: str) -> void {
rt_statusbuf[i] = 0
}
fn rt_status_text() -> ptr {
function rt_status_text() -> ptr {
return rt_statusbuf
}
@ -460,7 +460,7 @@ fn 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.
fn rt_save_state(f: ptr) -> void {
function rt_save_state(f: ptr) -> void {
let w: words = bytes(16)
w[0] = rt_rng
w[1] = rt_mapw
@ -473,7 +473,7 @@ fn rt_save_state(f: ptr) -> void {
free(w)
}
fn rt_load_state(f: ptr) -> void {
function rt_load_state(f: ptr) -> void {
let w: words = bytes(16)
file_read(f, w, 16)
rt_rng = w[0]

View file

@ -21,7 +21,7 @@ var img_n: int = 0
var spr_px: words = null # SPR_MAX * 16 * 16 RGBA pixels, one block
var spr_n: int = 0
fn rt_image_init() -> void {
function rt_image_init() -> void {
img_px = bytes(IMG_MAX * 8)
img_w = words(IMG_MAX)
img_h = words(IMG_MAX)
@ -30,11 +30,11 @@ fn rt_image_init() -> void {
}
# ---- decoding -------------------------------------------------------------
fn png_be32(b: ptr, at: int) -> int {
function png_be32(b: ptr, at: int) -> int {
return (b[at] << 24) | (b[at + 1] << 16) | (b[at + 2] << 8) | b[at + 3]
}
fn png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool {
function png_tag(b: ptr, 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 @@ fn png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool {
return true
}
fn rt_read_file(path: str) -> ptr {
function rt_read_file(path: str) -> ptr {
let f = file_open(path, "rb")
if (f == null) { return null }
file_seek(f, 0, 2)
@ -62,7 +62,7 @@ var png_w: int = 0
var png_h: int = 0
var png_px: words = null
fn rt_decode_png(path: str) -> bool {
function rt_decode_png(path: str) -> bool {
png_w = 0
png_h = 0
png_px = null
@ -227,7 +227,7 @@ fn rt_decode_png(path: str) -> bool {
}
# ---- images ---------------------------------------------------------------
fn rt_image_load(path: str) -> int {
function rt_image_load(path: str) -> int {
if img_n >= IMG_MAX { return 0 - 1 }
if rt_decode_png(path) == false { return 0 - 1 }
let id = img_n
@ -238,7 +238,7 @@ fn rt_image_load(path: str) -> int {
return id
}
fn rt_blend_px(x: int, y: int, argb: int) -> void {
function rt_blend_px(x: int, y: int, argb: int) -> void {
let a = ((argb >> 24) & 255)
if a == 0 { return }
if x < 0 { return }
@ -260,7 +260,7 @@ fn rt_blend_px(x: int, y: int, argb: int) -> void {
rt_fb[y * rt_fbw + x] = (((r << 16) | (g << 8)) | b)
}
fn rt_draw_image(id: int, dx: int, dy: int) -> void {
function rt_draw_image(id: int, dx: int, dy: int) -> void {
if id < 0 { return }
if id >= img_n { return }
let w = img_w[id]
@ -273,7 +273,7 @@ fn rt_draw_image(id: int, dx: int, dy: int) -> void {
}
}
fn rt_draw_image_scaled(id: int, dx: int, dy: int, dw: int, dh: int) -> void {
function rt_draw_image_scaled(id: int, dx: int, dy: int, dw: int, dh: int) -> void {
if id < 0 { return }
if id >= img_n { return }
if dw <= 0 { return }
@ -290,7 +290,7 @@ fn rt_draw_image_scaled(id: int, dx: int, dy: int, dw: int, dh: int) -> void {
# map one destination axis onto the source for a 9-slice: the two insets are
# copied 1:1 and only the middle stretches
fn rt_9map(d: int, dsz: int, ssz: int, inset: int) -> int {
function rt_9map(d: int, dsz: int, ssz: int, inset: int) -> int {
if inset * 2 >= dsz { return d * ssz / max(dsz, 1) }
if inset * 2 >= ssz { return d * ssz / max(dsz, 1) }
if d < inset { return d }
@ -298,7 +298,7 @@ fn rt_9map(d: int, dsz: int, ssz: int, inset: int) -> int {
return inset + (d - inset) * (ssz - 2 * inset) / (dsz - 2 * inset)
}
fn rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int) -> void {
function rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int) -> void {
if id < 0 { return }
if id >= img_n { return }
if dw <= 0 { return }
@ -315,7 +315,7 @@ fn rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int) -> vo
}
# ---- sprites (16x16 art) --------------------------------------------------
fn rt_png_load(path: str) -> int {
function rt_png_load(path: str) -> int {
if spr_n >= SPR_MAX { return 0 - 1 }
if rt_decode_png(path) == false { return 0 - 1 }
let id = spr_n
@ -338,7 +338,7 @@ fn rt_png_load(path: str) -> int {
return id
}
fn rt_draw_sprite(id: int, px: int, py: int) -> void {
function rt_draw_sprite(id: int, px: int, py: int) -> void {
if id < 0 { return }
if id >= spr_n { return }
let base = id * SPR_SZ * SPR_SZ
@ -352,7 +352,7 @@ fn rt_draw_sprite(id: int, px: int, py: int) -> void {
}
}
fn rt_draw_sprite_scaled(id: int, px: int, py: int, sc: int) -> void {
function rt_draw_sprite_scaled(id: int, px: int, py: int, sc: int) -> void {
if id < 0 { return }
if id >= spr_n { return }
if sc < 1 { return }
@ -368,14 +368,14 @@ fn rt_draw_sprite_scaled(id: int, px: int, py: int, sc: int) -> void {
}
# ---- .lspr sprite sheets (palette + ASCII rows) ---------------------------
fn rt_hexval(c: int) -> int {
function rt_hexval(c: int) -> int {
if c >= 48 { if c <= 57 { return c - 48 } }
if c >= 97 { if c <= 102 { return c - 87 } }
if c >= 65 { if c <= 70 { return c - 55 } }
return 0 - 1
}
fn rt_sprites_load(path: str) -> void {
function rt_sprites_load(path: str) -> void {
let d = rt_read_file(path)
if (d == null) { spr_n = 0; return }
let size = rt_file_len

View file

@ -20,7 +20,7 @@ var z_bitbuf: int = 0
var z_bitcnt: int = 0
var z_err: int = 0
fn z_start(src: ptr, len: int) -> void {
function z_start(src: ptr, len: int) -> void {
z_src = src
z_len = len
z_pos = 0
@ -29,7 +29,7 @@ fn z_start(src: ptr, len: int) -> void {
z_err = 0
}
fn z_bits(need: int) -> int {
function z_bits(need: int) -> int {
var val = z_bitbuf
while z_bitcnt < need {
if z_pos >= z_len {
@ -48,12 +48,12 @@ fn 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.
fn z_table_new(nsym: int) -> ptr {
function z_table_new(nsym: int) -> ptr {
return words((16 + nsym))
}
# lengths[i] = code length of symbol i (0 = symbol unused)
fn z_table_build(table: words, lengths: words, n: int) -> void {
function z_table_build(table: words, lengths: words, n: int) -> void {
for i in 0 .. 16 {
table[i] = 0
}
@ -78,7 +78,7 @@ fn z_table_build(table: words, lengths: words, n: int) -> void {
free(offs)
}
fn z_decode(table: words) -> int {
function z_decode(table: words) -> int {
var code = 0
var first = 0
var index = 0
@ -97,7 +97,7 @@ fn z_decode(table: words) -> int {
}
# ---- length / distance code tables (RFC 1951 section 3.2.5) ---------------
fn z_len_base(sym: int) -> int {
function z_len_base(sym: int) -> int {
if sym < 8 { return 3 + sym }
if sym == 28 { return 258 }
let extra = (sym - 4) / 4
@ -105,27 +105,27 @@ fn z_len_base(sym: int) -> int {
return 3 + ((group - 1) << 2) + 4 + (sym - 4 - extra * 4) * group
}
fn z_len_extra(sym: int) -> int {
function z_len_extra(sym: int) -> int {
if sym < 8 { return 0 }
if sym == 28 { return 0 }
return (sym - 4) / 4
}
fn z_dist_base(sym: int) -> int {
function z_dist_base(sym: int) -> int {
if sym < 4 { return 1 + sym }
let extra = (sym - 2) / 2
let group = (1 << extra)
return 1 + (group << 1) + (sym - 2 - extra * 2) * group
}
fn z_dist_extra(sym: int) -> int {
function z_dist_extra(sym: int) -> int {
if sym < 4 { return 0 }
return (sym - 2) / 2
}
# ---- block decoders -------------------------------------------------------
# `out` is the destination window; returns the new write position, or -1.
fn z_stored(out: ptr, at: int, cap: int) -> int {
function z_stored(out: ptr, 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 @@ fn z_stored(out: ptr, at: int, cap: int) -> int {
return w
}
fn z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int {
function z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int {
var w = at
var sym = z_decode(lit)
while sym != 256 {
@ -172,7 +172,7 @@ fn z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int {
return w
}
fn z_fixed_tables(lit: ptr, dist: ptr) -> void {
function z_fixed_tables(lit: ptr, dist: ptr) -> 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 @@ fn z_fixed_tables(lit: ptr, dist: ptr) -> void {
free(lengths)
}
fn z_dynamic_tables(lit: ptr, dist: ptr) -> int {
function z_dynamic_tables(lit: ptr, dist: ptr) -> int {
let nlen = z_bits(5) + 257
let ndist = z_bits(5) + 1
let ncode = z_bits(4) + 4
@ -240,7 +240,7 @@ fn z_dynamic_tables(lit: ptr, dist: ptr) -> int {
}
# Inflate a raw DEFLATE stream. Returns bytes written, or -1.
fn z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int {
function z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int {
z_start(src, len)
let lit = z_table_new(288)
let dist = z_table_new(30)
@ -268,7 +268,7 @@ fn z_inflate(src: ptr, len: int, out: ptr, cap: int) -> int {
}
# zlib wrapper (RFC 1950): two header bytes, then DEFLATE, then Adler-32.
fn z_uncompress(src: ptr, len: int, out: ptr, cap: int) -> int {
function z_uncompress(src: ptr, len: int, out: ptr, cap: int) -> int {
if len < 2 { return -1 }
let cmf = src[0]
if (cmf & 15) != 8 { return -1 }

View file

@ -63,7 +63,7 @@ var gc_oy: words = null
var gc_adv: words = null
var gc_bmp: ptrs = null
fn rt_tt_init() -> void {
function rt_tt_init() -> void {
tt_data = bytes(TT_MAX * 8)
tt_size = words(TT_MAX)
tt_upem = words(TT_MAX)
@ -105,24 +105,24 @@ fn rt_tt_init() -> void {
}
# ---- big-endian readers ---------------------------------------------------
fn tt_u16(d: ptr, at: int) -> int {
function tt_u16(d: ptr, at: int) -> int {
return ((d[at] << 8) | d[at + 1])
}
fn tt_i16(d: ptr, at: int) -> int {
function tt_i16(d: ptr, at: int) -> int {
let v = tt_u16(d, at)
if v >= 32768 { return v - 65536 }
return v
}
fn tt_u32(d: ptr, at: int) -> int {
function tt_u32(d: ptr, at: int) -> int {
return (d[at] << 24) | (d[at + 1] << 16) | (d[at + 2] << 8) | d[at + 3]
}
fn tt_i8(d: ptr, at: int) -> int {
function tt_i8(d: ptr, at: int) -> int {
let v = d[at]
if v >= 128 { return v - 256 }
return v
}
fn tt_find_table(d: ptr, base: int, a: int, b: int, c: int, e: int) -> int {
function tt_find_table(d: ptr, 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 @@ fn 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
fn tt_pick_cmap(id: int, d: ptr, co: int) -> void {
function tt_pick_cmap(id: int, d: ptr, co: int) -> void {
tt_cmap[id] = 0 - 1
tt_cfmt[id] = 0
if co < 0 { return }
@ -166,7 +166,7 @@ fn tt_pick_cmap(id: int, d: ptr, co: int) -> void {
tt_cfmt[id] = tt_u16(d, best)
}
fn rt_font_load(path: str) -> int {
function rt_font_load(path: str) -> int {
if tt_n >= TT_MAX { return 0 - 1 }
let d = rt_read_file(path)
if (d == null) { return 0 - 1 }
@ -212,7 +212,7 @@ fn rt_font_load(path: str) -> int {
}
# ---- codepoint -> glyph id ------------------------------------------------
fn tt_glyph_index(id: int, cp: int) -> int {
function tt_glyph_index(id: int, cp: int) -> int {
let d = tt_data[id]
let s = tt_cmap[id]
if s < 0 { return 0 }
@ -261,7 +261,7 @@ fn tt_glyph_index(id: int, cp: int) -> int {
return 0
}
fn tt_advance(id: int, gid: int) -> int {
function tt_advance(id: int, gid: int) -> int {
let d = tt_data[id]
let hmtx = tt_hmtx[id]
let n = tt_nhm[id]
@ -270,7 +270,7 @@ fn tt_advance(id: int, gid: int) -> int {
}
# ---- outline extraction ---------------------------------------------------
fn ol_pt(x: fixed, y: fixed, on: int) -> void {
function ol_pt(x: fixed, y: fixed, on: int) -> void {
if ol_n >= TT_PTS { return }
ol_x[ol_n] = x
ol_y[ol_n] = y
@ -278,13 +278,13 @@ fn ol_pt(x: fixed, y: fixed, on: int) -> void {
ol_n = ol_n + 1
}
fn tt_glyph_start(id: int, gid: int) -> int {
function tt_glyph_start(id: int, gid: int) -> int {
let d = tt_data[id]
let loca = tt_loca[id]
if tt_locfm[id] == 0 { return tt_u16(d, loca + gid * 2) * 2 }
return tt_u32(d, loca + gid * 4)
}
fn tt_glyph_end(id: int, gid: int) -> int {
function tt_glyph_end(id: int, gid: int) -> int {
let d = tt_data[id]
let loca = tt_loca[id]
if tt_locfm[id] == 0 { return tt_u16(d, loca + (gid + 1) * 2) * 2 }
@ -292,7 +292,7 @@ fn tt_glyph_end(id: int, gid: int) -> int {
}
# Append glyph `gid`, transformed by [a b c e] + (dx,dy), to the outline.
fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx: fixed, dy: fixed, depth: int) -> void {
function tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx: fixed, dy: fixed, depth: int) -> void {
if gid < 0 { return }
if gid >= tt_nglyf[id] { return }
if depth > 5 { return }

View file

@ -2,7 +2,7 @@
# and text drawing. Split out of truetype.ludic (the sfnt/cmap/outline half).
# ---- rasterization --------------------------------------------------------
fn ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void {
function ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void {
if ed_n >= TT_EDGES { return }
ed_x0[ed_n] = x0
ed_y0[ed_n] = y0
@ -11,7 +11,7 @@ fn ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void {
ed_n = ed_n + 1
}
fn tt_isqrt(v: int) -> int {
function tt_isqrt(v: int) -> int {
if v <= 0 { return 0 }
var r = 0
var b = 32768
@ -24,7 +24,7 @@ fn tt_isqrt(v: int) -> int {
}
# flatten one quadratic Bézier into line segments, subdivided by chord length
fn ed_quad(x0: fixed, y0: fixed, cx: fixed, cy: fixed, x1: fixed, y1: fixed) -> void {
function ed_quad(x0: fixed, y0: fixed, cx: fixed, cy: fixed, x1: fixed, y1: fixed) -> void {
let dx = flr(x1) - flr(x0)
let dy = flr(y1) - flr(y0)
var n = tt_isqrt(dx * dx + dy * dy) / 3
@ -51,7 +51,7 @@ var gr_ox: int = 0
var gr_oy: int = 0
var gr_adv: int = 0
fn tt_raster(id: int, gid: int, px: int) -> ptr {
function tt_raster(id: int, gid: int, px: int) -> ptr {
let upem = tt_upem[id]
let scale = fx(px) / upem
gr_adv = flr(fx(tt_advance(id, gid)) * scale + 0.5)
@ -231,11 +231,11 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
# ---- glyph cache ----------------------------------------------------------
# Rasterizing is far too slow to repeat per frame, so a coverage mask is kept
# per (font, codepoint, size). Open addressing, 8 probes, evict on miss.
fn gc_hash(font: int, cp: int, px: int) -> int {
function gc_hash(font: int, cp: int, px: int) -> int {
return ((((cp * 2654435761) ^ (font << 20)) ^ (px << 8)) & (TT_GC - 1))
}
fn tt_glyph_get(font: int, cp: int, px: int) -> int {
function tt_glyph_get(font: int, cp: int, px: int) -> int {
let h = gc_hash(font, cp, px)
for k in 0 .. 8 {
let s = ((h + k) & (TT_GC - 1))
@ -269,7 +269,7 @@ fn tt_glyph_get(font: int, cp: int, px: int) -> int {
# ---- UTF-8 ----------------------------------------------------------------
var u8_next: int = 0 # byte index just past the codepoint last decoded
fn tt_utf8(s: str, at: int) -> int {
function tt_utf8(s: str, at: int) -> int {
let c = s[at]
var extra = 0 - 1
if c < 128 { extra = 0 }
@ -298,7 +298,7 @@ fn tt_utf8(s: str, at: int) -> int {
}
# ---- drawing --------------------------------------------------------------
fn tt_blit(bmp: ptr, w: int, h: int, dx: int, dy: int, colour: int) -> void {
function tt_blit(bmp: ptr, 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)
@ -327,7 +327,7 @@ fn tt_blit(bmp: ptr, w: int, h: int, dx: int, dy: int, colour: int) -> void {
}
}
fn rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void {
function rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void {
if font < 0 { return }
if font >= tt_n { return }
if px <= 0 { return }
@ -351,7 +351,7 @@ fn rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void
}
}
fn rt_text_w(font: int, s: str, px: int) -> int {
function rt_text_w(font: int, s: str, px: int) -> int {
if font < 0 { return 0 }
if font >= tt_n { return 0 }
if px <= 0 { return 0 }
@ -372,7 +372,7 @@ fn rt_text_w(font: int, s: str, px: int) -> int {
return best
}
fn rt_text_h(font: int, px: int) -> int {
function rt_text_h(font: int, px: int) -> int {
if font < 0 { return 0 }
if font >= tt_n { return 0 }
let scale = fx(px) / tt_upem[font]

View file

@ -79,7 +79,7 @@ var ui_n: int = 0
var ui_active: int = -1
var ui_focus: int = -1
fn rt_ui_init() -> void {
function rt_ui_init() -> void {
ui_type = words(UI_MAX)
ui_parent = words(UI_MAX)
ui_w = words(UI_MAX)
@ -112,7 +112,7 @@ fn rt_ui_init() -> void {
}
# ---- build-time interface (called by compiler-emitted code) ---------------
fn rt_ui_reset(n: int) -> void {
function rt_ui_reset(n: int) -> void {
ui_n = n
for i in 0 .. n {
ui_type[i] = 0
@ -142,7 +142,7 @@ fn rt_ui_reset(n: int) -> void {
}
}
fn rt_ui_set(i: int, k: int, v: int) -> void {
function rt_ui_set(i: int, k: int, v: int) -> void {
if i < 0 { return }
if i >= UI_MAX { return }
if k == K_TYPE { ui_type[i] = v }
@ -168,21 +168,21 @@ fn rt_ui_set(i: int, k: int, v: int) -> void {
if k == K_SKIN { ui_skin[i] = v }
}
fn rt_ui_static_text(i: int, s: str) -> void {
function rt_ui_static_text(i: int, s: str) -> void {
if i < 0 { return }
if i >= UI_MAX { return }
ui_text[i] = s
}
# ---- text helpers: TrueType when a font is loaded, bitmap otherwise -------
fn ui_str(i: int) -> ptr {
function ui_str(i: int) -> ptr {
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
}
fn 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: ptr, 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 @@ fn ui_draw_text(font: int, x: int, y: int, s: ptr, colour: int, size: int) -> vo
rt_text(x, y, s, colour, max(size / 8, 1))
}
fn ui_tw(font: int, s: ptr, size: int) -> int {
function ui_tw(font: int, s: ptr, size: int) -> int {
if font >= 0 {
if font < tt_n { return rt_text_w(font, s, size) }
}
@ -201,24 +201,24 @@ fn ui_tw(font: int, s: ptr, size: int) -> int {
return n * 6 * max(size / 8, 1)
}
fn ui_th(font: int, size: int) -> int {
function ui_th(font: int, size: int) -> int {
if font >= 0 {
if font < tt_n { return rt_text_h(font, size) }
}
return 7 * max(size / 8, 1)
}
fn ui_is_container(t: int) -> bool {
function ui_is_container(t: int) -> bool {
if t == WT_PANEL { return true }
if t == WT_COL { return true }
if t == WT_ROW { return true }
return false
}
fn ui_dir(t: int) -> int {
function ui_dir(t: int) -> int {
if t == WT_ROW { return 0 }
return 1
}
fn ui_under(i: int, root: int) -> bool {
function ui_under(i: int, root: int) -> bool {
var k = i
while k >= 0 {
if k == root { return true }
@ -228,7 +228,7 @@ fn ui_under(i: int, root: int) -> bool {
}
# ---- measure: content sizes, children before parents ----------------------
fn ui_measure() -> void {
function ui_measure() -> void {
var i = ui_n - 1
while i >= 0 {
if ui_visible[i] == 0 {
@ -303,7 +303,7 @@ fn ui_measure() -> void {
}
}
fn ui_eff_align(child: int, parent: int) -> int {
function ui_eff_align(child: int, parent: int) -> int {
if ui_align[child] >= 0 { return ui_align[child] }
if ui_align[parent] >= 0 { return ui_align[parent] }
return 0

View file

@ -2,7 +2,7 @@
# accessors. Split out of ui.ludic (the storage/build/measure half).
# ---- arrange: rects, parents before children ------------------------------
fn ui_arrange(i: int, x: int, y: int) -> void {
function ui_arrange(i: int, x: int, y: int) -> void {
ui_rx[i] = x
ui_ry[i] = y
let t = ui_type[i]
@ -61,7 +61,7 @@ fn ui_arrange(i: int, x: int, y: int) -> void {
}
}
fn ui_layout() -> void {
function ui_layout() -> void {
if ui_active < 0 { return }
ui_measure()
var px = (rt_fbw - ui_rw[ui_active]) / 2
@ -74,7 +74,7 @@ fn ui_layout() -> void {
}
# ---- drawing --------------------------------------------------------------
fn ui_lighten(c: int) -> int {
function ui_lighten(c: int) -> int {
var r = ((c >> 16) & 255)
var g = ((c >> 8) & 255)
var b = (c & 255)
@ -84,7 +84,7 @@ fn ui_lighten(c: int) -> int {
return (((r << 16) | (g << 8)) | b)
}
fn ui_draw_node(i: int) -> void {
function ui_draw_node(i: int) -> void {
if ui_visible[i] == 0 { return }
let t = ui_type[i]
let rx = ui_rx[i]
@ -148,7 +148,7 @@ fn ui_draw_node(i: int) -> void {
# ---- focus and activation -------------------------------------------------
var ui_fl: words = null
fn ui_focusables() -> int {
function ui_focusables() -> int {
if (ui_fl == null) { ui_fl = words(UI_MAX) }
var n = 0
for i in 0 .. ui_n {
@ -164,14 +164,14 @@ fn ui_focusables() -> int {
return n
}
fn rt_ui_open(root: int) -> void {
function rt_ui_open(root: int) -> void {
ui_active = root
let n = ui_focusables()
ui_focus = 0 - 1
if n > 0 { ui_focus = ui_fl[0] }
}
fn rt_ui_tick(k: int) -> void {
function rt_ui_tick(k: int) -> void {
if ui_active < 0 { return }
for i in 0 .. ui_n { ui_fired[i] = 0 }
ui_layout()
@ -201,20 +201,20 @@ fn rt_ui_tick(k: int) -> void {
if k == 13 { ui_fired[ui_focus] = 1 }
}
fn rt_ui_render() -> void {
function rt_ui_render() -> void {
if ui_active < 0 { return }
ui_layout()
ui_draw_node(ui_active)
}
# ---- game-facing accessors ------------------------------------------------
fn rt_ui_clicked(id: int) -> bool {
function rt_ui_clicked(id: int) -> bool {
if id < 0 { return false }
if id >= ui_n { return false }
return ui_fired[id] == 1
}
fn rt_ui_set_text(id: int, s: str) -> void {
function rt_ui_set_text(id: int, s: str) -> void {
if id < 0 { return }
if id >= ui_n { return }
let base = id * 96
@ -232,7 +232,7 @@ fn rt_ui_set_text(id: int, s: str) -> void {
ui_hasdyn[id] = 1
}
fn rt_ui_set_int(id: int, n: int) -> void {
function rt_ui_set_int(id: int, n: int) -> void {
if id < 0 { return }
if id >= ui_n { return }
let base = id * 96
@ -266,17 +266,17 @@ fn rt_ui_set_int(id: int, n: int) -> void {
ui_hasdyn[id] = 1
}
fn rt_ui_focus(id: int) -> void {
function rt_ui_focus(id: int) -> void {
if id < 0 { return }
if id >= ui_n { return }
ui_focus = id
}
fn rt_ui_focused() -> int {
function rt_ui_focused() -> int {
return ui_focus
}
fn rt_ui_visible(id: int, v: int) -> void {
function rt_ui_visible(id: int, v: int) -> void {
if id < 0 { return }
if id >= ui_n { return }
ui_visible[id] = v