Merge Phase 6f: let/var mutability model
This commit is contained in:
commit
0e0c58519d
38 changed files with 2909 additions and 2778 deletions
36
LANGUAGE.md
36
LANGUAGE.md
|
|
@ -466,11 +466,37 @@ another `.ludic` file (see `examples/lib/`).
|
|||
|
||||
## Statements
|
||||
|
||||
`let x = expr` · `x = expr` (`+= -= *= /=`) · `if cond { }` / `if/else`
|
||||
(the `else` is optional) · `while cond { }` · `for i in a .. b { }` (numeric range) ·
|
||||
`for (…) in query […] { }` · `break` · `continue` · `return` · `spawn` ·
|
||||
`despawn` · `enable` / `disable` (a property `on e`, a model, or a handler) ·
|
||||
`match` · `machine`.
|
||||
`let x = expr` / `var x = expr` · `x = expr` (`+= -= *= /=`) · `if cond { }` /
|
||||
`if/else` (the `else` is optional) · `while cond { }` · `for i in a .. b { }`
|
||||
(numeric range) · `for (…) in query […] { }` · `break` · `continue` · `return` ·
|
||||
`spawn` · `despawn` · `enable` / `disable` (a property `on e`, a model, or a
|
||||
handler) · `match` · `machine`.
|
||||
|
||||
### Bindings: `let`, `var`, `const`
|
||||
|
||||
A binding's keyword states whether it can be reassigned, the way Rust and Swift
|
||||
use them — not its scope (position decides that: inside a body it is a local,
|
||||
at the top level it is module state).
|
||||
|
||||
- **`let x = e`** — an *immutable* binding. `x = …` afterward is a compile error
|
||||
(`cannot assign to immutable 'x'`). Reach for `let` by default.
|
||||
- **`var x = e`** — a *mutable* binding: `x`, `x += 1`, … reassign it. Use it for
|
||||
loop accumulators and anything that genuinely changes.
|
||||
- **`const NAME = e`** — a compile-time constant (folded, no storage).
|
||||
|
||||
Immutability is of the **binding**, not the object. A `let` that holds a record
|
||||
or slice still lets you mutate *through* it — the reference itself just cannot be
|
||||
repointed:
|
||||
|
||||
```ludic
|
||||
# doc-check: skip — illustrative bindings
|
||||
let n = new Node # immutable binding…
|
||||
n.kind = 1 # …but mutation through it is fine
|
||||
n = new Node # ERROR: cannot assign to immutable 'n'
|
||||
|
||||
var total = 0
|
||||
for i in 0 .. 10 { total += i } # a var is the right tool for an accumulator
|
||||
```
|
||||
|
||||
**Statements are separated by a newline or `;`** (both lex to the same separator
|
||||
token). Two statements may not sit adjacent with only spaces between them — the
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@ handler Battle phase Update {
|
|||
|
||||
state EnemyTurn {
|
||||
if k != 0 {
|
||||
let done = 0
|
||||
var done = 0
|
||||
for (t3) in query [Stats, {Party}] {
|
||||
if done == 0 {
|
||||
if t3.hp > 0 {
|
||||
let ed = max(1, e.atk - t3.def + rng_range(0, 4))
|
||||
var ed = max(1, e.atk - t3.def + rng_range(0, 4))
|
||||
if t3.guard == 1 { ed = ed / 2; t3.guard = 0 }
|
||||
t3.hp = t3.hp - ed
|
||||
set_reg(R_EDMG, ed)
|
||||
|
|
@ -128,7 +128,7 @@ handler Battle phase Update {
|
|||
}
|
||||
}
|
||||
}
|
||||
let alive = 0
|
||||
var alive = 0
|
||||
for (t4) in query [Stats, {Party}] {
|
||||
if t4.hp > 0 { alive = alive + 1 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ handler Draw phase Render {
|
|||
clear(0x101018)
|
||||
|
||||
if m == 0 {
|
||||
let cx = 0
|
||||
let cy = 0
|
||||
var cx = 0
|
||||
var cy = 0
|
||||
for (p) in query [Pos, {Player}] {
|
||||
cx = clamp(p.x * 16 - 152, 0, MW * 16 - 320)
|
||||
cy = clamp(p.y * 16 - 112, 0, MH * 16 - 240)
|
||||
|
|
@ -18,7 +18,7 @@ handler Draw phase Render {
|
|||
let c = tile(tx, ty)
|
||||
let sx = tx * 16 - cx
|
||||
let sy = ty * 16 - cy
|
||||
let base = SPR_GRASS
|
||||
var base = SPR_GRASS
|
||||
match c {
|
||||
'r' => base = SPR_PATH
|
||||
',', 'S', 'B' => base = SPR_FLOOR
|
||||
|
|
@ -57,7 +57,7 @@ handler Draw phase Render {
|
|||
if m == 1 {
|
||||
fill_rect(0, 0, 320, 176, 0x241a2e)
|
||||
for (e, a) in query [Stats, Actor, {Enemy}] {
|
||||
let bs = 5
|
||||
var bs = 5
|
||||
if reg(R_ETYPE) == 2 { bs = 7 }
|
||||
draw_sprite_scaled(a.kind, 160 - bs * 8, 44, bs)
|
||||
text(100, 20, enemy_name(reg(R_ETYPE)), 0xffffff, 1)
|
||||
|
|
@ -65,14 +65,14 @@ handler Draw phase Render {
|
|||
fill_rect(100, 30, e.hp * 120 / e.maxhp, 8, 0xe04040)
|
||||
}
|
||||
let ph = reg(R_PHASE)
|
||||
let act = 0
|
||||
var act = 0
|
||||
if ph >= 2 { act = 1 }
|
||||
if ph >= 4 { act = 2 }
|
||||
fill_rect(0, 176, 320, 64, 0x0c0c16)
|
||||
frame_rect(0, 176, 320, 64, 0x3a3a55)
|
||||
for (st, pt) in query [Stats, Party] {
|
||||
let hx = 6 + pt.slot * 92
|
||||
let spr = 5
|
||||
var spr = 5
|
||||
if pt.slot == 1 { spr = 9 }
|
||||
if pt.slot == act { frame_rect(hx - 2, 180, 88, 44, 0xffff00) }
|
||||
draw_sprite_scaled(spr, hx, 184, 2)
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ handler Control phase Input {
|
|||
if reg(R_MODE) == 0 {
|
||||
for (p) in query [Pos, {Player}] {
|
||||
let k = key()
|
||||
let nx = p.x
|
||||
let ny = p.y
|
||||
var nx = p.x
|
||||
var ny = p.y
|
||||
if k == 'w' { ny = p.y - 1 }
|
||||
if k == 's' { ny = p.y + 1 }
|
||||
if k == 'a' { nx = p.x - 1 }
|
||||
if k == 'd' { nx = p.x + 1 }
|
||||
let moved = 0
|
||||
var moved = 0
|
||||
if walkable(nx, ny) {
|
||||
if nx != p.x or ny != p.y {
|
||||
p.x = nx
|
||||
|
|
@ -88,7 +88,7 @@ handler Control phase Input {
|
|||
set_reg(R_ENC, reg(R_ENC) - 1)
|
||||
if reg(R_ENC) <= 0 {
|
||||
set_reg(R_ENC, rng_range(4, 9))
|
||||
let et = 0
|
||||
var et = 0
|
||||
if reg(R_MAP) == 1 { et = 1 }
|
||||
if reg(R_MAP) == 0 {
|
||||
if rng_chance(40) { et = 1 }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ program Combat {
|
|||
|
||||
# damage after armour, with a crit multiplier applied on an exact roll
|
||||
@export fn damage(attack: int, armour: int, roll: int) -> int {
|
||||
let raw = attack - armour
|
||||
var raw = attack - armour
|
||||
if raw < 1 { raw = 1 }
|
||||
if roll == 20 { raw = raw * CRIT_MULT }
|
||||
return raw
|
||||
|
|
@ -26,8 +26,8 @@ program Combat {
|
|||
# how many hits to drop a target — the loop is here so the caller cannot
|
||||
# accidentally disagree with `damage` about rounding
|
||||
@export fn hits_to_kill(hp: int, attack: int, armour: int) -> int {
|
||||
let left = hp
|
||||
let n = 0
|
||||
var left = hp
|
||||
var n = 0
|
||||
while left > 0 {
|
||||
left = left - damage(attack, armour, 0)
|
||||
n = n + 1
|
||||
|
|
|
|||
|
|
@ -114,14 +114,14 @@ program Snake {
|
|||
clear(0x0d1020)
|
||||
for gy in 0 .. GH {
|
||||
for gx in 0 .. GW {
|
||||
let col = 0x141a2e
|
||||
var col = 0x141a2e
|
||||
if (gx + gy) % 2 == 0 { col = 0x10162a }
|
||||
fill_rect(gx * TS, gy * TS, TS, TS, col)
|
||||
}
|
||||
}
|
||||
fill_rect(reg(R_FX) * TS + 3, reg(R_FY) * TS + 3, TS - 6, TS - 6, 0xe0405a)
|
||||
for (p, s) in query [Pos, Seg] {
|
||||
let col = 0x40c060
|
||||
var col = 0x40c060
|
||||
if s.order == 0 { col = 0x9dffb0 }
|
||||
fill_rect(p.x * TS + 1, p.y * TS + 1, TS - 2, TS - 2, col)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ program Toggles {
|
|||
|
||||
handler Run phase Render {
|
||||
for (e) in query [Player] { disable Shield on self() } # @OnDisable -> 6
|
||||
let n = 0
|
||||
var n = 0
|
||||
for (s) in query [Shield] { n += 1 }
|
||||
print_int(n) # 0 — no live Shield now
|
||||
|
||||
|
|
|
|||
|
|
@ -79,10 +79,10 @@ fn rt_fill_rect(x: int, y: int, w: int, h: int, c: int) -> void {
|
|||
let y0 = max(0, y)
|
||||
let x1 = min(rt_fbw, x + w)
|
||||
let y1 = min(rt_fbh, y + h)
|
||||
let j = y0
|
||||
var j = y0
|
||||
while j < y1 {
|
||||
let row = j * rt_fbw
|
||||
let i = x0
|
||||
var i = x0
|
||||
while i < x1 {
|
||||
poke32(rt_fb, row + i, c)
|
||||
i = i + 1
|
||||
|
|
@ -108,7 +108,7 @@ fn rt_present() -> void {
|
|||
|
||||
# ---- text -----------------------------------------------------------------
|
||||
fn rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
|
||||
let c = ch
|
||||
var c = ch
|
||||
if c >= 97 {
|
||||
if c <= 122 { c = c - 32 }
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ fn rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
|
|||
let font = rt_font()
|
||||
for row in 0 .. 7 {
|
||||
let bits = peek8(font, base + row) - 48
|
||||
let b = bits
|
||||
var b = bits
|
||||
for cc in 0 .. 5 {
|
||||
let on = b / 16
|
||||
if on == 1 {
|
||||
|
|
@ -130,9 +130,9 @@ 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 {
|
||||
let i = 0
|
||||
let cx = x
|
||||
let ch = peek8(s, 0)
|
||||
var i = 0
|
||||
var cx = x
|
||||
var ch = peek8(s, 0)
|
||||
while ch != 0 {
|
||||
rt_glyph(cx, y, ch, colour, sc)
|
||||
cx = cx + 6 * sc
|
||||
|
|
@ -146,22 +146,22 @@ fn rt_text_int(x: int, y: int, n: int, colour: int, sc: int) -> void {
|
|||
rt_glyph(x, y, 48, colour, sc)
|
||||
return
|
||||
}
|
||||
let v = n
|
||||
let cx = x
|
||||
var v = n
|
||||
var cx = x
|
||||
if v < 0 {
|
||||
rt_glyph(cx, y, 45, colour, sc)
|
||||
cx = cx + 6 * sc
|
||||
v = 0 - v
|
||||
}
|
||||
let digits = 0
|
||||
let t = v
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
}
|
||||
let p = digits
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
let div = 1
|
||||
var div = 1
|
||||
for k in 1 .. p {
|
||||
div = div * 10
|
||||
}
|
||||
|
|
@ -196,7 +196,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 {
|
||||
let x = rt_rng
|
||||
var x = rt_rng
|
||||
x = bxor(x, shl(x, 13))
|
||||
x = bxor(x, shr(x, 17))
|
||||
x = bxor(x, shl(x, 5))
|
||||
|
|
@ -238,9 +238,9 @@ fn rt_running() -> bool {
|
|||
|
||||
# ---- writing the frame out ------------------------------------------------
|
||||
fn rt_put_str(buf: ptr, at: int, s: str) -> int {
|
||||
let i = 0
|
||||
let n = at
|
||||
let ch = peek8(s, 0)
|
||||
var i = 0
|
||||
var n = at
|
||||
var ch = peek8(s, 0)
|
||||
while ch != 0 {
|
||||
poke8(buf, n, ch)
|
||||
n = n + 1
|
||||
|
|
@ -255,16 +255,16 @@ fn rt_put_int(buf: ptr, at: int, v: int) -> int {
|
|||
poke8(buf, at, 48)
|
||||
return at + 1
|
||||
}
|
||||
let digits = 0
|
||||
let t = v
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
}
|
||||
let n = at
|
||||
let p = digits
|
||||
var n = at
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
let div = 1
|
||||
var div = 1
|
||||
for k in 1 .. p {
|
||||
div = div * 10
|
||||
}
|
||||
|
|
@ -280,7 +280,7 @@ fn rt_dump_ppm(path: str) -> void {
|
|||
if ptr_is_null(f) { return }
|
||||
|
||||
let hdr = mem_alloc(64)
|
||||
let n = rt_put_str(hdr, 0, "P6\n")
|
||||
var n = rt_put_str(hdr, 0, "P6\n")
|
||||
n = rt_put_int(hdr, n, rt_fbw)
|
||||
n = rt_put_str(hdr, n, " ")
|
||||
n = rt_put_int(hdr, n, rt_fbh)
|
||||
|
|
@ -323,8 +323,8 @@ fn rt_map_size(w: int, h: int) -> void {
|
|||
fn rt_map_row(y: int, s: str) -> void {
|
||||
if y < 0 { return }
|
||||
if y >= 64 { return }
|
||||
let x = 0
|
||||
let ch = peek8(s, 0)
|
||||
var x = 0
|
||||
var ch = peek8(s, 0)
|
||||
while ch != 0 {
|
||||
if x >= 96 { return }
|
||||
poke8(rt_map, y * 96 + x, ch)
|
||||
|
|
@ -347,8 +347,8 @@ fn rt_tile(x: int, y: int) -> int {
|
|||
var rt_statusbuf: ptr = ptr_null()
|
||||
|
||||
fn rt_status(s: str) -> void {
|
||||
let i = 0
|
||||
let ch = peek8(s, 0)
|
||||
var i = 0
|
||||
var ch = peek8(s, 0)
|
||||
while ch != 0 {
|
||||
if i >= 95 { ch = 0 }
|
||||
if ch != 0 {
|
||||
|
|
|
|||
|
|
@ -74,17 +74,17 @@ fn rt_decode_png(path: str) -> bool {
|
|||
if peek8(d, 0) != 137 { mem_free(d); return false }
|
||||
if peek8(d, 1) != 80 { mem_free(d); return false }
|
||||
|
||||
let w = 0
|
||||
let h = 0
|
||||
let bd = 0
|
||||
let ct = 0
|
||||
var w = 0
|
||||
var h = 0
|
||||
var bd = 0
|
||||
var ct = 0
|
||||
let plte = mem_alloc(768)
|
||||
let trns = mem_alloc(256)
|
||||
let ntrns = 0
|
||||
var ntrns = 0
|
||||
let idat = mem_alloc(size)
|
||||
let idlen = 0
|
||||
let i = 8
|
||||
let done = 0
|
||||
var idlen = 0
|
||||
var i = 8
|
||||
var done = 0
|
||||
|
||||
while done == 0 {
|
||||
if i + 8 > size { done = 1 }
|
||||
|
|
@ -122,12 +122,12 @@ fn rt_decode_png(path: str) -> bool {
|
|||
if w <= 0 { mem_free(d); return false }
|
||||
if h <= 0 { mem_free(d); return false }
|
||||
|
||||
let channels = 1
|
||||
var channels = 1
|
||||
if ct == 2 { channels = 3 }
|
||||
if ct == 6 { channels = 4 }
|
||||
if ct == 4 { channels = 2 }
|
||||
let bppbits = bd * channels
|
||||
let fbpp = (bppbits + 7) / 8
|
||||
var fbpp = (bppbits + 7) / 8
|
||||
if fbpp < 1 { fbpp = 1 }
|
||||
let stride = (w * bppbits + 7) / 8
|
||||
let rawlen = h * (stride + 1)
|
||||
|
|
@ -144,13 +144,13 @@ fn rt_decode_png(path: str) -> bool {
|
|||
let cur = line + 1
|
||||
let prev = cur - (stride + 1)
|
||||
for x in 0 .. stride {
|
||||
let a = 0
|
||||
let b = 0
|
||||
let c = 0
|
||||
var a = 0
|
||||
var b = 0
|
||||
var c = 0
|
||||
if x >= fbpp { a = peek8(raw, cur + x - fbpp) }
|
||||
if y > 0 { b = peek8(raw, prev + x) }
|
||||
if x >= fbpp { if y > 0 { c = peek8(raw, prev + x - fbpp) } }
|
||||
let v = peek8(raw, cur + x)
|
||||
var v = peek8(raw, cur + x)
|
||||
if ft == 1 { v = v + a }
|
||||
if ft == 2 { v = v + b }
|
||||
if ft == 3 { v = v + (a + b) / 2 }
|
||||
|
|
@ -159,7 +159,7 @@ fn rt_decode_png(path: str) -> bool {
|
|||
let pa = abs(p - a)
|
||||
let pb = abs(p - b)
|
||||
let pc = abs(p - c)
|
||||
let pick = c
|
||||
var pick = c
|
||||
if pb <= pc { pick = b }
|
||||
if pa <= pb { if pa <= pc { pick = a } }
|
||||
v = v + pick
|
||||
|
|
@ -174,10 +174,10 @@ fn rt_decode_png(path: str) -> bool {
|
|||
for y in 0 .. h {
|
||||
let row = y * (stride + 1) + 1
|
||||
for x in 0 .. w {
|
||||
let R = 0
|
||||
let G = 0
|
||||
let B = 0
|
||||
let A = 255
|
||||
var R = 0
|
||||
var G = 0
|
||||
var B = 0
|
||||
var A = 255
|
||||
if ct == 6 {
|
||||
R = peek8(raw, row + x * 4)
|
||||
G = peek8(raw, row + x * 4 + 1)
|
||||
|
|
@ -206,7 +206,7 @@ fn rt_decode_png(path: str) -> bool {
|
|||
if ct == 0 {
|
||||
let bp = x * bd
|
||||
let s = band(shr(peek8(raw, row + bp / 8), 8 - bd - bp % 8), maxv)
|
||||
let g = s
|
||||
var g = s
|
||||
if bd != 8 { g = s * 255 / maxv }
|
||||
R = g
|
||||
G = g
|
||||
|
|
@ -246,9 +246,9 @@ fn rt_blend_px(x: int, y: int, argb: int) -> void {
|
|||
if y < 0 { return }
|
||||
if x >= rt_fbw { return }
|
||||
if y >= rt_fbh { return }
|
||||
let r = band(shr(argb, 16), 255)
|
||||
let g = band(shr(argb, 8), 255)
|
||||
let b = band(argb, 255)
|
||||
var r = band(shr(argb, 16), 255)
|
||||
var g = band(shr(argb, 8), 255)
|
||||
var b = band(argb, 255)
|
||||
if a != 255 {
|
||||
let dst = peek32(rt_fb, y * rt_fbw + x)
|
||||
let dr = band(shr(dst, 16), 255)
|
||||
|
|
@ -324,7 +324,7 @@ fn rt_png_load(path: str) -> int {
|
|||
let base = id * SPR_SZ * SPR_SZ
|
||||
for y in 0 .. SPR_SZ {
|
||||
for x in 0 .. SPR_SZ {
|
||||
let px = 0
|
||||
var px = 0
|
||||
if x < png_w {
|
||||
if y < png_h {
|
||||
let c = peek32(png_px, y * png_w + x)
|
||||
|
|
@ -382,13 +382,13 @@ fn rt_sprites_load(path: str) -> void {
|
|||
let size = rt_file_len
|
||||
let pal = mem_alloc(128 * 4)
|
||||
mem_set(pal, 0, 128 * 4)
|
||||
let cur = 0 - 1
|
||||
let row = 0
|
||||
let i = 0
|
||||
var cur = 0 - 1
|
||||
var row = 0
|
||||
var i = 0
|
||||
while i < size {
|
||||
let start = i
|
||||
let len = 0
|
||||
let j = start
|
||||
var len = 0
|
||||
var j = start
|
||||
while j < size {
|
||||
let ch = peek8(d, j)
|
||||
if ch == 10 { j = size } else { len = len + 1; j = j + 1 }
|
||||
|
|
@ -396,7 +396,7 @@ fn rt_sprites_load(path: str) -> void {
|
|||
let c0 = peek8(d, start)
|
||||
if c0 == 112 { # 'p' — "pal <char> <rrggbb>"
|
||||
let ch = peek8(d, start + 4)
|
||||
let v = 0
|
||||
var v = 0
|
||||
for k in 0 .. 6 {
|
||||
let hv = rt_hexval(peek8(d, start + 6 + k))
|
||||
if hv >= 0 { v = v * 16 + hv }
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn z_start(src: ptr, len: int) -> void {
|
|||
}
|
||||
|
||||
fn z_bits(need: int) -> int {
|
||||
let val = z_bitbuf
|
||||
var val = z_bitbuf
|
||||
while z_bitcnt < need {
|
||||
if z_pos >= z_len {
|
||||
z_err = 1
|
||||
|
|
@ -79,9 +79,9 @@ fn z_table_build(table: ptr, lengths: ptr, n: int) -> void {
|
|||
}
|
||||
|
||||
fn z_decode(table: ptr) -> int {
|
||||
let code = 0
|
||||
let first = 0
|
||||
let index = 0
|
||||
var code = 0
|
||||
var first = 0
|
||||
var index = 0
|
||||
for len in 1 .. 16 {
|
||||
code = bor(code, z_bits(1))
|
||||
let count = peek32(table, len)
|
||||
|
|
@ -131,7 +131,7 @@ fn z_stored(out: ptr, at: int, cap: int) -> int {
|
|||
if z_pos + 4 > z_len { return -1 }
|
||||
let n = peek8(z_src, z_pos) + shl(peek8(z_src, z_pos + 1), 8)
|
||||
z_pos = z_pos + 4 # LEN then its one's complement
|
||||
let w = at
|
||||
var w = at
|
||||
for i in 0 .. n {
|
||||
if z_pos >= z_len { return -1 }
|
||||
if w >= cap { return -1 }
|
||||
|
|
@ -143,8 +143,8 @@ fn z_stored(out: ptr, at: int, cap: int) -> int {
|
|||
}
|
||||
|
||||
fn z_codes(out: ptr, at: int, cap: int, lit: ptr, dist: ptr) -> int {
|
||||
let w = at
|
||||
let sym = z_decode(lit)
|
||||
var w = at
|
||||
var sym = z_decode(lit)
|
||||
while sym != 256 {
|
||||
if z_err != 0 { return -1 }
|
||||
if sym < 0 { return -1 }
|
||||
|
|
@ -202,7 +202,7 @@ fn z_dynamic_tables(lit: ptr, dist: ptr) -> int {
|
|||
let clen = z_table_new(19)
|
||||
z_table_build(clen, lengths, 19)
|
||||
|
||||
let n = 0
|
||||
var n = 0
|
||||
while n < nlen + ndist {
|
||||
let sym = z_decode(clen)
|
||||
if sym < 0 { return 0 }
|
||||
|
|
@ -211,8 +211,8 @@ fn z_dynamic_tables(lit: ptr, dist: ptr) -> int {
|
|||
n = n + 1
|
||||
}
|
||||
if sym >= 16 {
|
||||
let prev = 0
|
||||
let rep = 0
|
||||
var prev = 0
|
||||
var rep = 0
|
||||
if sym == 16 {
|
||||
if n == 0 { return 0 }
|
||||
prev = peek32(lengths, n - 1)
|
||||
|
|
@ -244,8 +244,8 @@ fn 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)
|
||||
let w = 0
|
||||
let final = 0
|
||||
var w = 0
|
||||
var final = 0
|
||||
while final == 0 {
|
||||
final = z_bits(1)
|
||||
let btype = z_bits(2)
|
||||
|
|
|
|||
|
|
@ -144,14 +144,14 @@ fn tt_pick_cmap(id: int, d: ptr, co: int) -> void {
|
|||
poke32(tt_cfmt, id, 0)
|
||||
if co < 0 { return }
|
||||
let n = tt_u16(d, co + 2)
|
||||
let best = 0 - 1
|
||||
let bestscore = 0 - 1
|
||||
var best = 0 - 1
|
||||
var bestscore = 0 - 1
|
||||
for i in 0 .. n {
|
||||
let rec = co + 4 + i * 8
|
||||
let plat = tt_u16(d, rec)
|
||||
let enc = tt_u16(d, rec + 2)
|
||||
let off = tt_u32(d, rec + 4)
|
||||
let score = 0 - 1
|
||||
var score = 0 - 1
|
||||
if plat == 0 { score = 2 }
|
||||
if plat == 0 { if enc == 4 { score = 4 } }
|
||||
if plat == 0 { if enc == 6 { score = 4 } }
|
||||
|
|
@ -172,7 +172,7 @@ fn rt_font_load(path: str) -> int {
|
|||
let d = rt_read_file(path)
|
||||
if ptr_is_null(d) { return 0 - 1 }
|
||||
let size = rt_file_len
|
||||
let base = 0
|
||||
var base = 0
|
||||
# a .ttc collection points at its first font
|
||||
if size >= 16 {
|
||||
if peek8(d, 0) == 116 { if peek8(d, 1) == 116 { if peek8(d, 2) == 99 { if peek8(d, 3) == 102 {
|
||||
|
|
@ -196,7 +196,7 @@ fn rt_font_load(path: str) -> int {
|
|||
tt_n = tt_n + 1
|
||||
pokep(tt_data, id, d)
|
||||
poke32(tt_size, id, size)
|
||||
let upem = tt_u16(d, head + 18)
|
||||
var upem = tt_u16(d, head + 18)
|
||||
if upem <= 0 { upem = 1000 }
|
||||
poke32(tt_upem, id, upem)
|
||||
poke32(tt_locfm, id, tt_i16(d, head + 50))
|
||||
|
|
@ -306,20 +306,20 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
|
||||
if nc >= 0 {
|
||||
let endpts = g + 10
|
||||
let npts = 0
|
||||
var npts = 0
|
||||
if nc > 0 { npts = tt_u16(d, endpts + (nc - 1) * 2) + 1 }
|
||||
let p = endpts + nc * 2
|
||||
var p = endpts + nc * 2
|
||||
p = p + 2 + tt_u16(d, p) # skip instructions
|
||||
|
||||
let flags = mem_alloc(npts + 8)
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < npts {
|
||||
let fl = peek8(d, p)
|
||||
p = p + 1
|
||||
poke8(flags, i, fl)
|
||||
i = i + 1
|
||||
if band(fl, 8) != 0 { # REPEAT
|
||||
let r = peek8(d, p)
|
||||
var r = peek8(d, p)
|
||||
p = p + 1
|
||||
while r > 0 {
|
||||
if i < npts { poke8(flags, i, fl); i = i + 1 }
|
||||
|
|
@ -330,7 +330,7 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
|
||||
let xs = mem_alloc((npts + 1) * 4)
|
||||
let ys = mem_alloc((npts + 1) * 4)
|
||||
let xv = 0
|
||||
var xv = 0
|
||||
for k in 0 .. npts {
|
||||
let fl = peek8(flags, k)
|
||||
if band(fl, 2) != 0 {
|
||||
|
|
@ -342,7 +342,7 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
}
|
||||
poke32(xs, k, xv)
|
||||
}
|
||||
let yv = 0
|
||||
var yv = 0
|
||||
for k in 0 .. npts {
|
||||
let fl = peek8(flags, k)
|
||||
if band(fl, 4) != 0 {
|
||||
|
|
@ -355,7 +355,7 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
poke32(ys, k, yv)
|
||||
}
|
||||
|
||||
let start = 0
|
||||
var start = 0
|
||||
for ci in 0 .. nc {
|
||||
let last = tt_u16(d, endpts + ci * 2)
|
||||
for k in start .. last + 1 {
|
||||
|
|
@ -374,14 +374,14 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
mem_free(ys)
|
||||
} else {
|
||||
# composite glyph: components, each with its own placement and transform
|
||||
let p = g + 10
|
||||
let more = 1
|
||||
var p = g + 10
|
||||
var more = 1
|
||||
while more == 1 {
|
||||
let flags = tt_u16(d, p)
|
||||
let cgid = tt_u16(d, p + 2)
|
||||
p = p + 4
|
||||
let arg1 = 0
|
||||
let arg2 = 0
|
||||
var arg1 = 0
|
||||
var arg2 = 0
|
||||
if band(flags, 1) != 0 {
|
||||
arg1 = tt_i16(d, p)
|
||||
arg2 = tt_i16(d, p + 2)
|
||||
|
|
@ -391,10 +391,10 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
arg2 = tt_i8(d, p + 1)
|
||||
p = p + 2
|
||||
}
|
||||
let ca = 1.0
|
||||
let cb = 0.0
|
||||
let cc = 0.0
|
||||
let ce = 1.0
|
||||
var ca = 1.0
|
||||
var cb = 0.0
|
||||
var cc = 0.0
|
||||
var ce = 1.0
|
||||
if band(flags, 8) != 0 {
|
||||
ca = as_fixed(shl(tt_i16(d, p), 2)) # F2Dot14 -> Q16.16
|
||||
ce = ca
|
||||
|
|
@ -412,8 +412,8 @@ fn tt_load_outline(id: int, gid: int, a: fixed, b: fixed, c: fixed, e: fixed, dx
|
|||
ce = as_fixed(shl(tt_i16(d, p + 6), 2))
|
||||
p = p + 8
|
||||
}
|
||||
let odx = dx
|
||||
let ody = dy
|
||||
var odx = dx
|
||||
var ody = dy
|
||||
if band(flags, 2) != 0 {
|
||||
odx = a * fx(arg1) + c * fx(arg2) + dx
|
||||
ody = b * fx(arg1) + e * fx(arg2) + dy
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ fn ed_add(x0: fixed, y0: fixed, x1: fixed, y1: fixed) -> void {
|
|||
|
||||
fn tt_isqrt(v: int) -> int {
|
||||
if v <= 0 { return 0 }
|
||||
let r = 0
|
||||
let b = 32768
|
||||
var r = 0
|
||||
var b = 32768
|
||||
while b > 0 {
|
||||
let t = r + b
|
||||
if t * t <= v { r = t }
|
||||
|
|
@ -27,11 +27,11 @@ fn tt_isqrt(v: int) -> int {
|
|||
fn 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)
|
||||
let n = tt_isqrt(dx * dx + dy * dy) / 3
|
||||
var n = tt_isqrt(dx * dx + dy * dy) / 3
|
||||
if n < 2 { n = 2 }
|
||||
if n > 24 { n = 24 }
|
||||
let px = x0
|
||||
let py = y0
|
||||
var px = x0
|
||||
var py = y0
|
||||
for i in 1 .. n + 1 {
|
||||
let t = fx(i) / n
|
||||
let u = 1.0 - t
|
||||
|
|
@ -63,10 +63,10 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
tt_load_outline(id, gid, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0)
|
||||
if ol_n == 0 { return ptr_null() }
|
||||
|
||||
let minx = 999999.0
|
||||
let miny = 999999.0
|
||||
let maxx = 0.0 - 999999.0
|
||||
let maxy = 0.0 - 999999.0
|
||||
var minx = 999999.0
|
||||
var miny = 999999.0
|
||||
var maxx = 0.0 - 999999.0
|
||||
var maxy = 0.0 - 999999.0
|
||||
for i in 0 .. ol_n {
|
||||
let X = peekf(ol_x, i) * scale
|
||||
let Y = peekf(ol_y, i) * scale
|
||||
|
|
@ -77,8 +77,8 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
}
|
||||
let x0 = flr(minx)
|
||||
let y0 = flr(miny)
|
||||
let x1 = flr(maxx) + 1
|
||||
let y1 = flr(maxy) + 1
|
||||
var x1 = flr(maxx) + 1
|
||||
var y1 = flr(maxy) + 1
|
||||
if maxx == fx(flr(maxx)) { x1 = flr(maxx) }
|
||||
if maxy == fx(flr(maxy)) { y1 = flr(maxy) }
|
||||
let W = x1 - x0
|
||||
|
|
@ -93,17 +93,17 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
gr_oy = y1
|
||||
|
||||
# build edges in supersample space (y grows downward)
|
||||
let start = 0
|
||||
var start = 0
|
||||
for ci in 0 .. ol_ne {
|
||||
let end = peek32(ol_ends, ci)
|
||||
let cnt = end - start
|
||||
if cnt >= 2 {
|
||||
let first_on = 0 - 1
|
||||
var first_on = 0 - 1
|
||||
for i in 0 .. cnt {
|
||||
if first_on < 0 { if peek32(ol_on, start + i) == 1 { first_on = i } }
|
||||
}
|
||||
let sx = 0.0
|
||||
let sy = 0.0
|
||||
var sx = 0.0
|
||||
var sy = 0.0
|
||||
if first_on < 0 {
|
||||
# all off-curve: start at the midpoint of the first and last point
|
||||
let mx = (peekf(ol_x, start) + peekf(ol_x, start + cnt - 1)) / 2
|
||||
|
|
@ -115,9 +115,9 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
sx = (peekf(ol_x, start + first_on) * scale - fx(x0)) * TT_SS
|
||||
sy = (fx(y1) - peekf(ol_y, start + first_on) * scale) * TT_SS
|
||||
}
|
||||
let curx = sx
|
||||
let cury = sy
|
||||
let step = 0
|
||||
var curx = sx
|
||||
var cury = sy
|
||||
var step = 0
|
||||
while step < cnt {
|
||||
let i = (first_on + 1 + step) % cnt
|
||||
let ix = (peekf(ol_x, start + i) * scale - fx(x0)) * TT_SS
|
||||
|
|
@ -127,11 +127,11 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
curx = ix
|
||||
cury = iy
|
||||
} else {
|
||||
let j = (i + 1) % cnt
|
||||
var j = (i + 1) % cnt
|
||||
let jx = (peekf(ol_x, start + j) * scale - fx(x0)) * TT_SS
|
||||
let jy = (fx(y1) - peekf(ol_y, start + j) * scale) * TT_SS
|
||||
let ex = jx
|
||||
let ey = jy
|
||||
var ex = jx
|
||||
var ey = jy
|
||||
if peek32(ol_on, start + j) == 1 {
|
||||
step = step + 1
|
||||
} else {
|
||||
|
|
@ -157,11 +157,11 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
|
||||
for sy in 0 .. SH {
|
||||
let yc = fx(sy) + 0.5
|
||||
let m = 0
|
||||
var m = 0
|
||||
for i in 0 .. ed_n {
|
||||
let ya = peekf(ed_y0, i)
|
||||
let yb = peekf(ed_y1, i)
|
||||
let hit = 0
|
||||
var hit = 0
|
||||
if ya <= yc { if yb > yc { hit = 1 } }
|
||||
if yb <= yc { if ya > yc { hit = 1 } }
|
||||
if hit == 1 {
|
||||
|
|
@ -175,8 +175,8 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
for i in 1 .. m {
|
||||
let kx = peekf(sc_x, i)
|
||||
let kd = peek32(sc_d, i)
|
||||
let j = i - 1
|
||||
let placed = 0
|
||||
var j = i - 1
|
||||
var placed = 0
|
||||
while j >= 0 {
|
||||
if peekf(sc_x, j) > kx {
|
||||
pokef(sc_x, j + 1, peekf(sc_x, j))
|
||||
|
|
@ -194,28 +194,28 @@ fn tt_raster(id: int, gid: int, px: int) -> ptr {
|
|||
poke32(sc_d, 0, kd)
|
||||
}
|
||||
}
|
||||
let wind = 0
|
||||
var wind = 0
|
||||
let oy = sy / TT_SS
|
||||
for i in 0 .. m - 1 {
|
||||
wind = wind + peek32(sc_d, i)
|
||||
if wind != 0 {
|
||||
let xa = peekf(sc_x, i)
|
||||
let xb = peekf(sc_x, i + 1)
|
||||
var xa = peekf(sc_x, i)
|
||||
var xb = peekf(sc_x, i + 1)
|
||||
if xa < 0.0 { xa = 0.0 }
|
||||
if xb > fx(SW) { xb = fx(SW) }
|
||||
if xb > xa {
|
||||
let ixa = flr(xa)
|
||||
let ixb = flr(xb) + 1
|
||||
for sx in ixa .. ixb {
|
||||
let cxl = xa
|
||||
let cxr = xb
|
||||
var cxl = xa
|
||||
var cxr = xb
|
||||
if fx(sx) > cxl { cxl = fx(sx) }
|
||||
if fx(sx + 1) < cxr { cxr = fx(sx + 1) }
|
||||
let cvr = cxr - cxl
|
||||
if cvr > 0.0 {
|
||||
let oxp = sx / TT_SS
|
||||
if oxp >= 0 { if oxp < W { if oy >= 0 { if oy < H {
|
||||
let v = peek8(cover, oy * W + oxp) + flr(cvr * unit)
|
||||
var v = peek8(cover, oy * W + oxp) + flr(cvr * unit)
|
||||
if v > 255 { v = 255 }
|
||||
poke8(cover, oy * W + oxp, v)
|
||||
} } } }
|
||||
|
|
@ -271,7 +271,7 @@ var u8_next: int = 0 # byte index just past the codepoint last decoded
|
|||
|
||||
fn tt_utf8(s: str, at: int) -> int {
|
||||
let c = peek8(s, at)
|
||||
let extra = 0 - 1
|
||||
var extra = 0 - 1
|
||||
if c < 128 { extra = 0 }
|
||||
if shr(c, 5) == 6 { extra = 1 }
|
||||
if shr(c, 4) == 14 { extra = 2 }
|
||||
|
|
@ -284,7 +284,7 @@ fn tt_utf8(s: str, at: int) -> int {
|
|||
u8_next = at + 1
|
||||
return c
|
||||
}
|
||||
let cp = band(c, shr(63, extra))
|
||||
var cp = band(c, shr(63, extra))
|
||||
for i in 0 .. extra {
|
||||
let b = peek8(s, at + 1 + i)
|
||||
if band(b, 192) != 128 {
|
||||
|
|
@ -333,10 +333,10 @@ fn rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void
|
|||
if px <= 0 { return }
|
||||
let upem = peek32(tt_upem, font)
|
||||
let scale = fx(px) / upem
|
||||
let baseline = y + flr(fx(peek32(tt_asc, font)) * scale + 0.5)
|
||||
var baseline = y + flr(fx(peek32(tt_asc, font)) * scale + 0.5)
|
||||
let lineh = flr(fx(peek32(tt_asc, font) - peek32(tt_desc, font) + peek32(tt_gap, font)) * scale + 0.5)
|
||||
let penx = x
|
||||
let i = 0
|
||||
var penx = x
|
||||
var i = 0
|
||||
while peek8(s, i) != 0 {
|
||||
let cp = tt_utf8(s, i)
|
||||
i = u8_next
|
||||
|
|
@ -355,9 +355,9 @@ fn 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 }
|
||||
let w = 0
|
||||
let best = 0
|
||||
let i = 0
|
||||
var w = 0
|
||||
var best = 0
|
||||
var i = 0
|
||||
while peek8(s, i) != 0 {
|
||||
let cp = tt_utf8(s, i)
|
||||
i = u8_next
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ fn ui_tw(font: int, s: ptr, size: int) -> int {
|
|||
if font >= 0 {
|
||||
if font < tt_n { return rt_text_w(font, s, size) }
|
||||
}
|
||||
let n = 0
|
||||
var n = 0
|
||||
while peek8(s, n) != 0 { n = n + 1 }
|
||||
return n * 6 * max(size / 8, 1)
|
||||
}
|
||||
|
|
@ -219,7 +219,7 @@ fn ui_dir(t: int) -> int {
|
|||
return 1
|
||||
}
|
||||
fn ui_under(i: int, root: int) -> bool {
|
||||
let k = i
|
||||
var k = i
|
||||
while k >= 0 {
|
||||
if k == root { return true }
|
||||
k = peek32(ui_parent, k)
|
||||
|
|
@ -229,7 +229,7 @@ fn ui_under(i: int, root: int) -> bool {
|
|||
|
||||
# ---- measure: content sizes, children before parents ----------------------
|
||||
fn ui_measure() -> void {
|
||||
let i = ui_n - 1
|
||||
var i = ui_n - 1
|
||||
while i >= 0 {
|
||||
if peek32(ui_visible, i) == 0 {
|
||||
poke32(ui_rw, i, 0)
|
||||
|
|
@ -237,8 +237,8 @@ fn ui_measure() -> void {
|
|||
} else {
|
||||
let t = peek32(ui_type, i)
|
||||
let pad = peek32(ui_pad, i)
|
||||
let cw = 0
|
||||
let ch = 0
|
||||
var cw = 0
|
||||
var ch = 0
|
||||
if t == WT_LABEL { cw = 0 - 1 }
|
||||
if t == WT_BUTTON { cw = 0 - 1 }
|
||||
if cw == 0 - 1 {
|
||||
|
|
@ -262,9 +262,9 @@ fn ui_measure() -> void {
|
|||
ch = peek32(ui_h, i)
|
||||
} else {
|
||||
let dir = ui_dir(t)
|
||||
let mainsz = 0
|
||||
let cross = 0
|
||||
let nc = 0
|
||||
var mainsz = 0
|
||||
var cross = 0
|
||||
var nc = 0
|
||||
for c in 0 .. ui_n {
|
||||
if peek32(ui_parent, c) == i {
|
||||
if peek32(ui_visible, c) == 1 {
|
||||
|
|
@ -292,8 +292,8 @@ fn ui_measure() -> void {
|
|||
}
|
||||
}
|
||||
}
|
||||
let rw = peek32(ui_w, i)
|
||||
let rh = peek32(ui_h, i)
|
||||
var rw = peek32(ui_w, i)
|
||||
var rh = peek32(ui_h, i)
|
||||
if rw == 0 { rw = cw }
|
||||
if rh == 0 { rh = ch }
|
||||
poke32(ui_rw, i, rw)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ fn ui_arrange(i: int, x: int, y: int) -> void {
|
|||
let gap = peek32(ui_gap, i)
|
||||
let innerw = peek32(ui_rw, i) - 2 * pad
|
||||
let innerh = peek32(ui_rh, i) - 2 * pad
|
||||
let total = 0
|
||||
let ng = 0
|
||||
let grows = 0
|
||||
var total = 0
|
||||
var ng = 0
|
||||
var grows = 0
|
||||
for c in 0 .. ui_n {
|
||||
if peek32(ui_parent, c) == i {
|
||||
if peek32(ui_visible, c) == 1 {
|
||||
|
|
@ -25,16 +25,16 @@ fn ui_arrange(i: int, x: int, y: int) -> void {
|
|||
}
|
||||
}
|
||||
if ng > 1 { total = total + gap * (ng - 1) }
|
||||
let avail = innerw
|
||||
var avail = innerw
|
||||
if dir == 1 { avail = innerh }
|
||||
let extra = max(avail - total, 0)
|
||||
let cx = x + pad
|
||||
let cy = y + pad
|
||||
var cx = x + pad
|
||||
var cy = y + pad
|
||||
for c in 0 .. ui_n {
|
||||
if peek32(ui_parent, c) == i {
|
||||
if peek32(ui_visible, c) == 1 {
|
||||
let kw = peek32(ui_rw, c)
|
||||
let kh = peek32(ui_rh, c)
|
||||
var kw = peek32(ui_rw, c)
|
||||
var kh = peek32(ui_rh, c)
|
||||
if peek32(ui_grow, c) != 0 {
|
||||
if grows > 0 {
|
||||
if dir == 1 { kh = kh + extra / grows } else { kw = kw + extra / grows }
|
||||
|
|
@ -44,13 +44,13 @@ fn ui_arrange(i: int, x: int, y: int) -> void {
|
|||
poke32(ui_rw, c, kw)
|
||||
poke32(ui_rh, c, kh)
|
||||
if dir == 1 {
|
||||
let ax = x + pad
|
||||
var ax = x + pad
|
||||
if al == 1 { ax = x + pad + (innerw - kw) / 2 }
|
||||
if al == 2 { ax = x + pad + (innerw - kw) }
|
||||
ui_arrange(c, ax, cy)
|
||||
cy = cy + kh + gap
|
||||
} else {
|
||||
let ay = y + pad
|
||||
var ay = y + pad
|
||||
if al == 1 { ay = y + pad + (innerh - kh) / 2 }
|
||||
if al == 2 { ay = y + pad + (innerh - kh) }
|
||||
ui_arrange(c, cx, ay)
|
||||
|
|
@ -64,8 +64,8 @@ fn ui_arrange(i: int, x: int, y: int) -> void {
|
|||
fn ui_layout() -> void {
|
||||
if ui_active < 0 { return }
|
||||
ui_measure()
|
||||
let px = (rt_fbw - peek32(ui_rw, ui_active)) / 2
|
||||
let py = (rt_fbh - peek32(ui_rh, ui_active)) / 2
|
||||
var px = (rt_fbw - peek32(ui_rw, ui_active)) / 2
|
||||
var py = (rt_fbh - peek32(ui_rh, ui_active)) / 2
|
||||
if peek32(ui_haspos, ui_active) == 1 {
|
||||
px = peek32(ui_x, ui_active)
|
||||
py = peek32(ui_y, ui_active)
|
||||
|
|
@ -75,9 +75,9 @@ fn ui_layout() -> void {
|
|||
|
||||
# ---- drawing --------------------------------------------------------------
|
||||
fn ui_lighten(c: int) -> int {
|
||||
let r = band(shr(c, 16), 255)
|
||||
let g = band(shr(c, 8), 255)
|
||||
let b = band(c, 255)
|
||||
var r = band(shr(c, 16), 255)
|
||||
var g = band(shr(c, 8), 255)
|
||||
var b = band(c, 255)
|
||||
r = r + (255 - r) * 4 / 10
|
||||
g = g + (255 - g) * 4 / 10
|
||||
b = b + (255 - b) * 4 / 10
|
||||
|
|
@ -92,7 +92,7 @@ fn ui_draw_node(i: int) -> void {
|
|||
let rw = peek32(ui_rw, i)
|
||||
let rh = peek32(ui_rh, i)
|
||||
let skin = peek32(ui_skin, i)
|
||||
let focused = 0
|
||||
var focused = 0
|
||||
if i == ui_focus { focused = 1 }
|
||||
|
||||
if t == WT_PANEL {
|
||||
|
|
@ -104,7 +104,7 @@ fn ui_draw_node(i: int) -> void {
|
|||
}
|
||||
}
|
||||
if t == WT_BUTTON {
|
||||
let bg = peek32(ui_bg, i)
|
||||
var bg = peek32(ui_bg, i)
|
||||
if bg < 0 { bg = 0x2a2a3a }
|
||||
if focused == 1 { bg = ui_lighten(bg) }
|
||||
if skin >= 0 {
|
||||
|
|
@ -112,12 +112,12 @@ fn ui_draw_node(i: int) -> void {
|
|||
} else {
|
||||
rt_fill_rect(rx, ry, rw, rh, bg)
|
||||
}
|
||||
let bc = peek32(ui_border, i)
|
||||
var bc = peek32(ui_border, i)
|
||||
if bc < 0 { bc = 0x555577 }
|
||||
if focused == 1 { bc = 0xffff00 }
|
||||
rt_frame_rect(rx, ry, rw, rh, bc)
|
||||
let s = ui_str(i)
|
||||
let fg = peek32(ui_fg, i)
|
||||
var fg = peek32(ui_fg, i)
|
||||
if fg < 0 { fg = 0xffffff }
|
||||
let font = peek32(ui_font, i)
|
||||
let size = peek32(ui_size, i)
|
||||
|
|
@ -125,13 +125,13 @@ fn ui_draw_node(i: int) -> void {
|
|||
}
|
||||
if t == WT_LABEL {
|
||||
let s = ui_str(i)
|
||||
let fg = peek32(ui_fg, i)
|
||||
var fg = peek32(ui_fg, i)
|
||||
if fg < 0 { fg = 0xffffff }
|
||||
let font = peek32(ui_font, i)
|
||||
let size = peek32(ui_size, i)
|
||||
let pad = peek32(ui_pad, i)
|
||||
let tw = ui_tw(font, s, size)
|
||||
let tx = rx + pad
|
||||
var tx = rx + pad
|
||||
let al = peek32(ui_align, i)
|
||||
if al == 1 { tx = rx + (rw - tw) / 2 }
|
||||
if al == 2 { tx = rx + rw - pad - tw }
|
||||
|
|
@ -150,7 +150,7 @@ var ui_fl: ptr = ptr_null()
|
|||
|
||||
fn ui_focusables() -> int {
|
||||
if ptr_is_null(ui_fl) { ui_fl = mem_alloc(UI_MAX * 4) }
|
||||
let n = 0
|
||||
var n = 0
|
||||
for i in 0 .. ui_n {
|
||||
if peek32(ui_focusable, i) == 1 {
|
||||
if peek32(ui_visible, i) == 1 {
|
||||
|
|
@ -180,7 +180,7 @@ fn rt_ui_tick(k: int) -> void {
|
|||
ui_focus = 0 - 1
|
||||
return
|
||||
}
|
||||
let cur = 0 - 1
|
||||
var cur = 0 - 1
|
||||
for i in 0 .. n {
|
||||
if peek32(ui_fl, i) == ui_focus { cur = i }
|
||||
}
|
||||
|
|
@ -218,8 +218,8 @@ fn rt_ui_set_text(id: int, s: str) -> void {
|
|||
if id < 0 { return }
|
||||
if id >= ui_n { return }
|
||||
let base = id * 96
|
||||
let i = 0
|
||||
let ch = peek8(s, 0)
|
||||
var i = 0
|
||||
var ch = peek8(s, 0)
|
||||
while ch != 0 {
|
||||
if i >= 95 { ch = 0 }
|
||||
if ch != 0 {
|
||||
|
|
@ -236,8 +236,8 @@ fn rt_ui_set_int(id: int, n: int) -> void {
|
|||
if id < 0 { return }
|
||||
if id >= ui_n { return }
|
||||
let base = id * 96
|
||||
let at = 0
|
||||
let v = n
|
||||
var at = 0
|
||||
var v = n
|
||||
if v < 0 {
|
||||
poke8(ui_dyn, base, 45)
|
||||
at = 1
|
||||
|
|
@ -247,15 +247,15 @@ fn rt_ui_set_int(id: int, n: int) -> void {
|
|||
poke8(ui_dyn, base + at, 48)
|
||||
at = at + 1
|
||||
} else {
|
||||
let digits = 0
|
||||
let t = v
|
||||
var digits = 0
|
||||
var t = v
|
||||
while t > 0 {
|
||||
digits = digits + 1
|
||||
t = t / 10
|
||||
}
|
||||
let p = digits
|
||||
var p = digits
|
||||
while p > 0 {
|
||||
let div = 1
|
||||
var div = 1
|
||||
for k in 1 .. p { div = div * 10 }
|
||||
poke8(ui_dyn, base + at, 48 + (v / div) % 10)
|
||||
at = at + 1
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ fn buf_putc(b: Buf, c: int) -> void {
|
|||
b.len = b.len + 1
|
||||
}
|
||||
fn buf_puts(b: Buf, s: ptr) -> void {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while peek8(s, i) != 0 { buf_putc(b, peek8(s, i)); i = i + 1 }
|
||||
}
|
||||
fn buf_puti(b: Buf, n: int) -> void { buf_puts(b, itoa(n)) }
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ var ll_str: int = 0 # string-constant counter
|
|||
var loc_name: []ptr
|
||||
var loc_reg: []ptr
|
||||
var loc_ty: []ptr
|
||||
var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let)
|
||||
var nloc: int = 0
|
||||
|
||||
# loop targets for break/continue (innermost last)
|
||||
|
|
@ -45,9 +46,9 @@ fn emit_alloca(llt: ptr) -> ptr {
|
|||
fn sconcat(a: ptr, b: ptr) -> ptr {
|
||||
let la = slen(a); let lb = slen(b)
|
||||
let out = mem_alloc(la + lb + 1)
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < la { poke8(out, i, peek8(a, i)); i = i + 1 }
|
||||
let j = 0
|
||||
var j = 0
|
||||
while j < lb { poke8(out, la + j, peek8(b, j)); j = j + 1 }
|
||||
poke8(out, la + lb, 0)
|
||||
return out
|
||||
|
|
@ -67,12 +68,12 @@ fn is_slice_ty(t: ptr) -> bool { return peek8(t, 0) == 91 and peek8(t, 1) == 93
|
|||
fn slice_elem(t: ptr) -> ptr { return substr(t, 2, slen(t) - 2) }
|
||||
|
||||
fn find_arch(name: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { let d = prog[i]; if d.kind == N_ARCH and streq(d.s, name) { return d }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
fn find_comp(name: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { let d = prog[i]; if d.kind == N_COMP and streq(d.s, name) { return d }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -82,19 +83,19 @@ fn layout_node(name: ptr) -> Node { return find_comp(name) }
|
|||
fn layout_ty(name: ptr) -> ptr { return sconcat("%Cmp_", name) }
|
||||
|
||||
fn field_index(s: Node, fname: ptr) -> int {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(s.kids) { if streq(s.kids[i].s, fname) { return i }; i = i + 1 }
|
||||
return 0 - 1
|
||||
}
|
||||
fn field_type(s: Node, fname: ptr) -> ptr {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(s.kids) { if streq(s.kids[i].s, fname) { return s.kids[i].ty }; i = i + 1 }
|
||||
return "int"
|
||||
}
|
||||
|
||||
# find a global var/const by name
|
||||
fn find_global(name: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if d.kind == N_VAR and streq(d.s, name) { return d }
|
||||
|
|
@ -107,11 +108,11 @@ fn 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.
|
||||
fn enum_ordinal(ename: ptr, vname: ptr) -> int {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if d.kind == N_ENUM and streq(d.s, ename) {
|
||||
let j = 0
|
||||
var j = 0
|
||||
while j < len(d.kids) { if streq(d.kids[j].s, vname) { return j }; j = j + 1 }
|
||||
}
|
||||
i = i + 1
|
||||
|
|
@ -119,7 +120,7 @@ fn enum_ordinal(ename: ptr, vname: ptr) -> int {
|
|||
return 0 - 1
|
||||
}
|
||||
fn find_fn(name: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { let d = prog[i]; if d.kind == N_FN and streq(d.s, name) { return d }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -136,7 +137,7 @@ fn register_computed(prop: ptr, field: ptr, ty: ptr, e: Node) -> void {
|
|||
fn computed_expr(prop: ptr, field: ptr) -> Node {
|
||||
if ptr_is_null(prop) { return ptr_null() }
|
||||
let key = sconcat(prop, sconcat(".", field))
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_computed) { if streq(g_computed[i].s, key) { return g_computed[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -155,7 +156,7 @@ fn register_onspawn(model: ptr, body: Node) -> void {
|
|||
let n = node(N_BLOCK); n.s = model; n.a = body; push(g_onspawn, n)
|
||||
}
|
||||
fn onspawn_body(model: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_onspawn) { if streq(g_onspawn[i].s, model) { return g_onspawn[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -170,7 +171,7 @@ fn register_ondespawn(model: ptr, body: Node) -> void {
|
|||
let n = node(N_BLOCK); n.s = model; n.a = body; push(g_ondespawn, n)
|
||||
}
|
||||
fn ondespawn_body(model: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_ondespawn) { if streq(g_ondespawn[i].s, model) { return g_ondespawn[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -178,7 +179,7 @@ fn register_onattach(prop: ptr, body: Node) -> void {
|
|||
let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_onattach, n)
|
||||
}
|
||||
fn onattach_body(prop: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_onattach) { if streq(g_onattach[i].s, prop) { return g_onattach[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -190,12 +191,12 @@ var g_ondisable: []Node
|
|||
fn register_onenable(prop: ptr, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_onenable, n) }
|
||||
fn register_ondisable(prop: ptr, body: Node) -> void { let n = node(N_BLOCK); n.s = prop; n.a = body; push(g_ondisable, n) }
|
||||
fn onenable_body(prop: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_onenable) { if streq(g_onenable[i].s, prop) { return g_onenable[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
fn ondisable_body(prop: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_ondisable) { if streq(g_ondisable[i].s, prop) { return g_ondisable[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
|
|
@ -205,13 +206,17 @@ fn is_model(name: ptr) -> bool { return find_arch_id(name) > 0 }
|
|||
|
||||
# local variable environment
|
||||
fn 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.
|
||||
fn loc_push(name: ptr, r: ptr, ty: ptr) -> void {
|
||||
if nloc < len(loc_name) { loc_name[nloc] = name; loc_reg[nloc] = r; loc_ty[nloc] = ty }
|
||||
else { push(loc_name, name); push(loc_reg, r); push(loc_ty, ty) }
|
||||
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
|
||||
}
|
||||
fn loc_set_mut(m: int) -> void { if nloc > 0 { loc_mut[nloc - 1] = m } }
|
||||
fn loc_find(name: ptr) -> int {
|
||||
let i = nloc - 1
|
||||
var i = nloc - 1
|
||||
while i >= 0 { if streq(loc_name[i], name) { return i }; i = i - 1 }
|
||||
return 0 - 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# ahead of it (see emit_alloca). Returns go through a %retval slot + `ret` label.
|
||||
|
||||
fn emit_params_sig(d: Node) -> void {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(d.kids) {
|
||||
if i > 0 { emit(", ") }
|
||||
emit(llty(d.kids[i].ty)); emit(" %arg_"); emit(d.kids[i].s)
|
||||
|
|
@ -21,7 +21,7 @@ fn emit_fn(d: Node) -> void {
|
|||
let rl = llty(ret_ty)
|
||||
if not streq(rl, "void") { buf_puts(falloc, " %retval = alloca "); buf_puts(falloc, rl); buf_puts(falloc, "\n") }
|
||||
# params: store each incoming argument into a stack slot
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(d.kids) {
|
||||
let p = d.kids[i]
|
||||
let slot = emit_alloca(llty(p.ty))
|
||||
|
|
@ -67,13 +67,13 @@ fn emit_main(d: Node) -> void {
|
|||
fn emit_program() -> void {
|
||||
head = buf_new()
|
||||
code = buf_new()
|
||||
loc_name = new []ptr; loc_reg = new []ptr; loc_ty = new []ptr
|
||||
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
|
||||
mach_stk = new []Node
|
||||
emit_header()
|
||||
if has_ecs() { emit_ecs_storage() }
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_FN { emit_fn(prog[i]) }; i = i + 1 }
|
||||
if has_ecs() { emit_ecs_allocator(); emit_snapshot() }
|
||||
if has_ui() { emit_ui_build() }
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
const MAX_ENT: int = 1024
|
||||
|
||||
fn has_systems() -> bool {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_SYS { return true }; i = i + 1 }
|
||||
return false
|
||||
}
|
||||
fn has_models() -> bool {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_ARCH { return true }; i = i + 1 }
|
||||
return false
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ fn emit_ecs_storage() -> void {
|
|||
emith(sconcat("@L_kind = internal global [", sconcat(me, " x i32] zeroinitializer\n")))
|
||||
emith(sconcat("@L_freelist = internal global [", sconcat(me, " x i32] zeroinitializer\n")))
|
||||
emith("@L_freen = internal global i32 0\n")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let c = prog[i]
|
||||
# per-entity storage for a property (its %Cmp_ layout is emitted in the
|
||||
|
|
@ -52,7 +52,7 @@ fn emit_ecs_storage() -> void {
|
|||
fn emit_ecs_allocator() -> void {
|
||||
let me = itoa(MAX_ENT)
|
||||
emit("define void @L_reset(i32 %e) {\nentry:\n")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
if prog[i].kind == N_COMP {
|
||||
let hn = sconcat("%h", itoa(i))
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn emit_bin(e: Node) -> Val {
|
|||
let b = emit_expr(e.b)
|
||||
let fx = streq(a.ty, "fixed") or streq(b.ty, "fixed")
|
||||
if is_cmp(e.s) {
|
||||
let ac = a.code; let bc = b.code
|
||||
var ac = a.code; var bc = b.code
|
||||
if fx { ac = to_fixed(a); bc = to_fixed(b) }
|
||||
let c = emit_bind(sconcat("icmp ", sconcat(cmp_code(e.s), sconcat(" i32 ", sconcat(ac, sconcat(", ", bc))))))
|
||||
return val(emit_bind(sconcat("zext i1 ", sconcat(c, " to i32"))), "bool")
|
||||
|
|
@ -100,8 +100,8 @@ fn emit_call(e: Node) -> Val {
|
|||
if is_intrinsic(name) { return emit_intrinsic(name, e) }
|
||||
if is_intrinsic2(name) { return emit_intrinsic2(name, e) }
|
||||
if is_math_builtin(name) { return emit_math_builtin(name, e) }
|
||||
let fn2 = find_fn(name)
|
||||
let cname = name
|
||||
var fn2 = find_fn(name)
|
||||
var cname = name
|
||||
if ptr_is_null(fn2) {
|
||||
# a builtin like clear()/reg() is satisfied by its rt_ function
|
||||
let rtname = sconcat("rt_", name)
|
||||
|
|
@ -112,11 +112,11 @@ fn emit_call(e: Node) -> Val {
|
|||
# evaluate args first (their IR is emitted before the call instruction)
|
||||
let args = new []ptr
|
||||
let atys = new []ptr
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(e.kids) { let v = emit_expr(e.kids[i]); push(args, v.code); push(atys, v.ty); i = i + 1 }
|
||||
let rl = llty(fn2.ty)
|
||||
emit(" ")
|
||||
let rreg = "0"
|
||||
var rreg = "0"
|
||||
if not streq(rl, "void") { rreg = nreg(); emit(rreg); emit(" = ") }
|
||||
emit("call "); emit(rl); emit(" @fn_"); emit(cname); emit("(")
|
||||
i = 0
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fn emit_system_fn(sys: Node) -> void {
|
|||
}
|
||||
|
||||
fn emit_calls_for_phase(phase: ptr) -> void {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if d.kind == N_SYS and streq(d.ty, phase) { # skip a disabled handler
|
||||
|
|
@ -39,7 +39,7 @@ fn emit_calls_for_phase(phase: ptr) -> void {
|
|||
# @OnDespawn(Model) hooks compile to `@on_despawn_<Model>(entity)` functions that
|
||||
# bind the model's properties and run the body — dispatched by kind at `despawn`.
|
||||
fn emit_despawn_hooks() -> void {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_ondespawn) {
|
||||
let hk = g_ondespawn[i]
|
||||
let model = find_arch(hk.s)
|
||||
|
|
@ -64,7 +64,7 @@ fn emit_despawn_hooks() -> void {
|
|||
|
||||
fn emit_game_main() -> void {
|
||||
# every system becomes a function first
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_SYS { emit_system_fn(prog[i]) }; i = i + 1 }
|
||||
emit_despawn_hooks()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ fn emit_str_const(s: ptr) -> ptr {
|
|||
let n = slen(s)
|
||||
emith(name); emith(" = private unnamed_addr constant [")
|
||||
emith(itoa(n + 1)); emith(" x i8] c\"")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < n {
|
||||
let c = peek8(s, i)
|
||||
if c == 34 or c == 92 or c < 32 or c > 126 {
|
||||
|
|
@ -79,13 +79,13 @@ fn emit_header() -> void {
|
|||
# property layouts — a %Cmp_ record of named fields, emitted here so `new`
|
||||
# works whether or not the program runs the ECS. The per-entity @S_/@H_ arrays
|
||||
# are separate (emit_ecs_storage), emitted only for a program that runs the ECS.
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if d.kind == N_COMP {
|
||||
emith(layout_ty(d.s)); emith(" = type { ")
|
||||
if len(d.kids) == 0 { emith("i32") }
|
||||
let f = 0
|
||||
var f = 0
|
||||
while f < len(d.kids) {
|
||||
if f > 0 { emith(", ") }
|
||||
emith(llty(d.kids[f].ty))
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ fn emit_intrinsic(name: ptr, e: Node) -> Val {
|
|||
if streq(name, "file_read") or streq(name, "file_write") {
|
||||
let f = arg_code(e, 0); let b = arg_code(e, 1); let n = arg_code(e, 2)
|
||||
let w = emit_bind(sconcat("zext i32 ", sconcat(n, " to i64")))
|
||||
let fn2 = "@fread"
|
||||
var fn2 = "@fread"
|
||||
if streq(name, "file_write") { fn2 = "@fwrite" }
|
||||
let r = emit_bind(sconcat("call i64 ", sconcat(fn2, sconcat("(ptr ", sconcat(b, sconcat(", i64 1, i64 ", sconcat(w, sconcat(", ptr ", sconcat(f, ")")))))))))
|
||||
return val(emit_bind(sconcat("trunc i64 ", sconcat(r, " to i32"))), "int")
|
||||
|
|
@ -117,7 +117,7 @@ fn emit_intrinsic(name: ptr, e: Node) -> Val {
|
|||
if streq(name, "bnot") { let a = arg_code(e, 0); return val(emit_bind(sconcat("xor i32 ", sconcat(a, ", -1"))), "int") }
|
||||
if streq(name,"shl") or streq(name,"shr") or streq(name,"band") or streq(name,"bor") or streq(name,"bxor") {
|
||||
let a = arg_code(e, 0); let b = arg_code(e, 1)
|
||||
let opc = "shl"
|
||||
var opc = "shl"
|
||||
if streq(name,"shr") { opc = "lshr" }
|
||||
if streq(name,"band") { opc = "and" }
|
||||
if streq(name,"bor") { opc = "or" }
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ fn emit_machine(st: Node) -> void {
|
|||
if nmach < len(mach_stk) { mach_stk[nmach] = st } else { push(mach_stk, st) }
|
||||
nmach = nmach + 1
|
||||
let endl = lbl("smend")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(st.kids) {
|
||||
let state = st.kids[i]
|
||||
let v = emit_expr(state.b)
|
||||
|
|
@ -29,8 +29,8 @@ fn emit_machine(st: Node) -> void {
|
|||
fn emit_become(st: Node) -> void {
|
||||
if nmach == 0 { perr("'become' outside a machine") }
|
||||
let m = mach_stk[nmach - 1]
|
||||
let target: Node = ptr_null()
|
||||
let i = 0
|
||||
var target: Node = ptr_null()
|
||||
var i = 0
|
||||
while i < len(m.kids) { if streq(m.kids[i].s, st.s) { target = m.kids[i] }; i = i + 1 }
|
||||
if ptr_is_null(target) { perr(sconcat("become: no state ", st.s)) }
|
||||
let regv = emit_expr(m.a)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ fn emit_math_builtin(name: ptr, e: Node) -> Val {
|
|||
}
|
||||
if streq(name, "min") or streq(name, "max") {
|
||||
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
|
||||
let op = "slt"
|
||||
var op = "slt"
|
||||
if streq(name, "max") { op = "sgt" }
|
||||
let c = emit_bind(sconcat("icmp ", sconcat(op, sconcat(" i32 ", sconcat(a.code, sconcat(", ", b.code))))))
|
||||
return val(emit_bind(sconcat("select i1 ", sconcat(c, sconcat(", i32 ", sconcat(a.code, sconcat(", i32 ", b.code)))))), "int")
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@ fn emit_new_struct(name: ptr) -> Val {
|
|||
let lty = layout_ty(name)
|
||||
let sz = emit_sizeof(lty)
|
||||
let obj = emit_bind(sconcat("call ptr @malloc(i64 ", sconcat(sz, ")")))
|
||||
let f = 0
|
||||
var f = 0
|
||||
while f < len(s.kids) {
|
||||
let fd = s.kids[f]
|
||||
let addr = nreg()
|
||||
emit(" "); emit(addr); emit(" = getelementptr inbounds "); emit(lty)
|
||||
emit(", ptr "); emit(obj); emit(", i32 0, i32 "); emit(itoa(f)); emit("\n")
|
||||
let lt = llty(fd.ty)
|
||||
let v = "0"
|
||||
var v = "0"
|
||||
if streq(lt, "ptr") { v = "null" }
|
||||
if not ptr_is_null(fd.a) { let dv = emit_expr(fd.a); v = dv.code }
|
||||
emit(" store "); emit(lt); emit(" "); emit(v); emit(", ptr "); emit(addr); emit("\n")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# the body once per match. Mirrors ll_query in compiler/back/ir_ecs.c.
|
||||
|
||||
fn find_arch_id(name: ptr) -> int {
|
||||
let i = 0; let n = 1
|
||||
var i = 0; var n = 1
|
||||
while i < len(prog) { if prog[i].kind == N_ARCH { if streq(prog[i].s, name) { return n }; n = n + 1 }; i = i + 1 }
|
||||
return 0
|
||||
}
|
||||
|
|
@ -34,11 +34,11 @@ fn emit_query(st: Node) -> void {
|
|||
|
||||
let terms = st.c
|
||||
# component / archetype filters
|
||||
let t = 0
|
||||
var t = 0
|
||||
while t < len(terms.kids) {
|
||||
let tm = terms.kids[t]
|
||||
let ak = find_arch_id(tm.s)
|
||||
let ok = "0"
|
||||
var ok = "0"
|
||||
if ak > 0 {
|
||||
let kp = nreg(); emit(" "); emit(kp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_kind, i32 0, i32 "); emit(i1); emit("\n")
|
||||
let kv = emit_bind(sconcat("load i32, ptr ", kp))
|
||||
|
|
@ -59,7 +59,7 @@ fn emit_query(st: Node) -> void {
|
|||
|
||||
# bind the requested components to the loop variables, in order
|
||||
let save = nloc
|
||||
let vi = 0
|
||||
var vi = 0
|
||||
t = 0
|
||||
while t < len(terms.kids) {
|
||||
let tm = terms.kids[t]
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ fn emit_snapshot_blocks(fn2: ptr) -> void {
|
|||
emit_io(fn2, "@L_alive", "%nalive")
|
||||
emit_io(fn2, "@L_freelist", "%nalive")
|
||||
emit_io(fn2, "@L_kind", "%nalive")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_VAR { emit_io(fn2, sconcat("@g_", prog[i].s), "4") }; i = i + 1 }
|
||||
let ci = 0
|
||||
var ci = 0
|
||||
i = 0
|
||||
while i < len(prog) {
|
||||
if prog[i].kind == N_COMP {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void {
|
|||
let slot = nreg()
|
||||
emit(" "); emit(slot); emit(" = getelementptr inbounds ["); emit(me); emit(" x %Cmp_"); emit(comp); emit("], ptr @S_"); emit(comp); emit(", i32 0, i32 "); emit(e); emit("\n")
|
||||
# defaults
|
||||
let f = 0
|
||||
var f = 0
|
||||
while f < len(c.kids) {
|
||||
let fd = c.kids[f]
|
||||
let addr = nreg()
|
||||
emit(" "); emit(addr); emit(" = getelementptr inbounds %Cmp_"); emit(comp); emit(", ptr "); emit(slot); emit(", i32 0, i32 "); emit(itoa(f)); emit("\n")
|
||||
let lt = llty(fd.ty)
|
||||
let v = "0"
|
||||
var v = "0"
|
||||
if streq(lt, "ptr") { v = "null" }
|
||||
if not ptr_is_null(fd.a) { let dv = emit_expr(fd.a); v = dv.code }
|
||||
emit(" store "); emit(lt); emit(" "); emit(v); emit(", ptr "); emit(addr); emit("\n")
|
||||
|
|
@ -24,7 +24,7 @@ fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void {
|
|||
}
|
||||
# per-spawn overrides
|
||||
if not ptr_is_null(rec) {
|
||||
let j = 0
|
||||
var j = 0
|
||||
while j < len(rec.kids) {
|
||||
let fi = rec.kids[j]
|
||||
let fidx = field_index(c, fi.s)
|
||||
|
|
@ -53,7 +53,7 @@ fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void {
|
|||
# @OnSpawn hook body can address them by name (like a query binding for one entity).
|
||||
fn emit_bind_props(model: Node, e: ptr) -> void {
|
||||
let me = itoa(MAX_ENT)
|
||||
let c = 0
|
||||
var c = 0
|
||||
while c < len(model.kids) {
|
||||
let pname = model.kids[c].s
|
||||
let slot = nreg()
|
||||
|
|
@ -73,11 +73,11 @@ fn emit_spawn(st: Node) -> void {
|
|||
let kp = nreg(); emit(" "); emit(kp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_kind, i32 0, i32 "); emit(e); emit("\n")
|
||||
emit(" store i32 "); emit(itoa(ak)); emit(", ptr "); emit(kp); emit("\n")
|
||||
let arch = find_arch(st.s)
|
||||
let c = 0
|
||||
var c = 0
|
||||
while c < len(arch.kids) {
|
||||
let cn = arch.kids[c].s
|
||||
let rec = ptr_null()
|
||||
let i = 0
|
||||
var rec = ptr_null()
|
||||
var i = 0
|
||||
while i < len(st.kids) { if streq(st.kids[i].s, cn) { rec = st.kids[i].a }; i = i + 1 }
|
||||
emit_init_component(e, cn, rec)
|
||||
c = c + 1
|
||||
|
|
@ -90,7 +90,7 @@ fn emit_spawn(st: Node) -> void {
|
|||
nloc = save
|
||||
}
|
||||
} else {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(st.kids) { emit_init_component(e, st.kids[i].s, st.kids[i].a); i = i + 1 }
|
||||
}
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ fn emit_despawn(st: Node) -> void {
|
|||
let me = itoa(MAX_ENT)
|
||||
let kp = nreg(); emit(" "); emit(kp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i32], ptr @L_kind, i32 0, i32 "); emit(v.code); emit("\n")
|
||||
let kind = emit_bind(sconcat("load i32, ptr ", kp))
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(g_ondespawn) {
|
||||
let mname = g_ondespawn[i].s
|
||||
let c = emit_bind(sconcat("icmp eq i32 ", sconcat(kind, sconcat(", ", itoa(find_arch_id(mname))))))
|
||||
|
|
@ -120,13 +120,13 @@ fn emit_despawn(st: Node) -> void {
|
|||
# data persists, so re-enabling restores it, and queries already skip a cleared
|
||||
# flag). A bare `<Model>` / `<Handler>` flips a global enabled flag.
|
||||
fn emit_toggle(st: Node) -> void {
|
||||
let val = "0"; if st.ival == 1 { val = "1" }
|
||||
var val = "0"; if st.ival == 1 { val = "1" }
|
||||
if not ptr_is_null(st.a) {
|
||||
let ev = emit_expr(st.a)
|
||||
let me = itoa(MAX_ENT)
|
||||
let hp = nreg(); emit(" "); emit(hp); emit(" = getelementptr inbounds ["); emit(me); emit(" x i8], ptr @H_"); emit(st.s); emit(", i32 0, i32 "); emit(ev.code); emit("\n")
|
||||
emit(" store i8 "); emit(val); emit(", ptr "); emit(hp); emit("\n")
|
||||
let hb: Node = ptr_null()
|
||||
var hb: Node = ptr_null()
|
||||
if st.ival == 1 { hb = onenable_body(st.s) } else { hb = ondisable_body(st.s) }
|
||||
if not ptr_is_null(hb) {
|
||||
let save = nloc
|
||||
|
|
@ -138,7 +138,7 @@ fn emit_toggle(st: Node) -> void {
|
|||
nloc = save
|
||||
}
|
||||
} else {
|
||||
let g = "@HE_"; if is_model(st.s) { g = "@ME_" } # model vs handler
|
||||
var g = "@HE_"; if is_model(st.s) { g = "@ME_" } # model vs handler
|
||||
emit(" store i32 "); emit(val); emit(", ptr "); emit(g); emit(st.s); emit("\n")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# block is skipped until a new basic block opens.
|
||||
|
||||
fn emit_block(b: Node) -> void {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(b.kids) {
|
||||
if g_term { return }
|
||||
emit_stmt(b.kids[i])
|
||||
|
|
@ -18,11 +18,16 @@ fn store_at(lt: ptr, v: ptr, addr: ptr) -> void {
|
|||
fn emit_assign(st: Node) -> void {
|
||||
# resolve the target's address and type
|
||||
let t = st.a
|
||||
let addr = "0"
|
||||
let ty = "int"
|
||||
var addr = "0"
|
||||
var ty = "int"
|
||||
if t.kind == E_ID {
|
||||
let li = loc_find(t.s)
|
||||
if li >= 0 { addr = loc_reg[li]; ty = loc_ty[li] }
|
||||
if li >= 0 {
|
||||
# a `let` binding is immutable: rebinding it is an error (mutating THROUGH
|
||||
# it — `x.field = …`, `x[i] = …` — is fine, and lands in the branches below).
|
||||
if loc_mut[li] == 0 { perr(sconcat("cannot assign to immutable '", sconcat(t.s, sconcat("' (declared with let; use var) — line ", itoa(st.line))))) }
|
||||
addr = loc_reg[li]; ty = loc_ty[li]
|
||||
}
|
||||
else {
|
||||
let g = find_global(t.s)
|
||||
if ptr_is_null(g) { perr(sconcat("assign to unknown ", t.s)) }
|
||||
|
|
@ -35,10 +40,10 @@ fn emit_assign(st: Node) -> void {
|
|||
}
|
||||
let lt = llty(ty)
|
||||
let rv = emit_expr(st.b)
|
||||
let v = rv.code
|
||||
var v = rv.code
|
||||
if not streq(st.s, "=") {
|
||||
let cur = emit_bind(sconcat("load ", sconcat(lt, sconcat(", ptr ", addr))))
|
||||
let opc = "add"
|
||||
var opc = "add"
|
||||
if streq(st.s, "-=") { opc = "sub" }
|
||||
if streq(st.s, "*=") { opc = "mul" }
|
||||
if streq(st.s, "/=") { opc = "sdiv" }
|
||||
|
|
@ -116,7 +121,7 @@ fn emit_return(st: Node) -> void {
|
|||
}
|
||||
|
||||
fn arm_is_default(arm: Node) -> bool {
|
||||
let p = 0
|
||||
var p = 0
|
||||
while p < len(arm.kids) { if arm.kids[p].kind == E_ID and streq(arm.kids[p].s, "_") { return true }; p = p + 1 }
|
||||
return false
|
||||
}
|
||||
|
|
@ -124,15 +129,15 @@ fn arm_is_default(arm: Node) -> bool {
|
|||
fn emit_match(st: Node) -> void {
|
||||
let sv = emit_expr(st.a)
|
||||
let endl = lbl("mend")
|
||||
let deflt: Node = ptr_null()
|
||||
let i = 0
|
||||
var deflt: Node = ptr_null()
|
||||
var i = 0
|
||||
while i < len(st.kids) {
|
||||
let arm = st.kids[i]
|
||||
if arm_is_default(arm) { deflt = arm }
|
||||
else {
|
||||
let acc = "0"
|
||||
let first = true
|
||||
let p = 0
|
||||
var acc = "0"
|
||||
var first = true
|
||||
var p = 0
|
||||
while p < len(arm.kids) {
|
||||
let pv = emit_expr(arm.kids[p])
|
||||
let c = emit_bind(sconcat("icmp eq i32 ", sconcat(sv.code, sconcat(", ", pv.code))))
|
||||
|
|
@ -156,16 +161,17 @@ fn emit_match(st: Node) -> void {
|
|||
|
||||
fn emit_stmt(st: Node) -> void {
|
||||
if st.kind == S_LET {
|
||||
let ty = st.ty
|
||||
var ty = st.ty
|
||||
if ptr_is_null(ty) { let v0 = emit_expr(st.a); ty = v0.ty
|
||||
let slot = emit_alloca(llty(ty)); store_at(llty(ty), v0.code, slot); loc_push(st.s, slot, ty); return }
|
||||
let slot = emit_alloca(llty(ty)); store_at(llty(ty), v0.code, slot); loc_push(st.s, slot, ty); loc_set_mut(st.ival); return }
|
||||
let slot = emit_alloca(llty(ty))
|
||||
if ptr_is_null(st.a) {
|
||||
let z = "0"
|
||||
var z = "0"
|
||||
if streq(llty(ty), "ptr") { z = "null" }
|
||||
store_at(llty(ty), z, slot)
|
||||
} else { let v = emit_expr(st.a); store_at(llty(ty), v.code, slot) }
|
||||
loc_push(st.s, slot, ty)
|
||||
loc_set_mut(st.ival)
|
||||
return
|
||||
}
|
||||
if st.kind == S_ASSIGN { emit_assign(st); return }
|
||||
|
|
|
|||
|
|
@ -15,26 +15,26 @@ fn ui_wtype(w: Node) -> int {
|
|||
return 0
|
||||
}
|
||||
fn ui_prop(w: Node, key: ptr) -> Node {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(w.b.kids) { if streq(w.b.kids[i].s, key) { return w.b.kids[i].a }; i = i + 1 }
|
||||
return ptr_null()
|
||||
}
|
||||
fn ui_flatten(w: Node, parent: int) -> void {
|
||||
let idx = len(uiw)
|
||||
push(uiw, w); push(uiw_parent, parent)
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(w.kids) { ui_flatten(w.kids[i], idx); i = i + 1 }
|
||||
}
|
||||
fn ui_flatten_all() -> void {
|
||||
uiw = new []Node; uiw_parent = new []int; ui_roots = new []int
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
if prog[i].kind == N_UI and prog[i].ival == 1 { push(ui_roots, len(uiw)); ui_flatten(prog[i].a, 0 - 1) }
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
fn has_ui() -> bool {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(prog) { if prog[i].kind == N_UI and prog[i].ival == 1 { return true }; i = i + 1 }
|
||||
return false
|
||||
}
|
||||
|
|
@ -42,8 +42,8 @@ fn has_ui() -> bool {
|
|||
# index of a UI_<name>: a ui block's root, or a widget's id=
|
||||
fn ui_index_of(nm: ptr) -> int {
|
||||
let s = substr(nm, 3, slen(nm) - 3) # strip "UI_"
|
||||
let u = 0; let bi = 0
|
||||
let i = 0
|
||||
let u = 0; var bi = 0
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
if prog[i].kind == N_UI and prog[i].ival == 1 { if streq(prog[i].s, s) { return ui_roots[bi] }; bi = bi + 1 }
|
||||
i = i + 1
|
||||
|
|
@ -79,14 +79,14 @@ fn emit_ui_build() -> void {
|
|||
let saved = code
|
||||
code = fbody
|
||||
emit(" call void @fn_rt_ui_reset(i32 "); emit(itoa(len(uiw))); emit(")\n")
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(uiw) {
|
||||
let w = uiw[i]
|
||||
let t = ui_wtype(w)
|
||||
ll_ui_set(i, 0, itoa(t))
|
||||
ll_ui_set(i, 1, itoa(uiw_parent[i]))
|
||||
if t == 4 { ll_ui_set(i, 17, "1") }
|
||||
let p = 0
|
||||
var p = 0
|
||||
while p < len(w.b.kids) {
|
||||
let pr = w.b.kids[p]
|
||||
let k = pr.s
|
||||
|
|
@ -101,7 +101,7 @@ fn emit_ui_build() -> void {
|
|||
if streq(k, "skin") { ll_ui_set(i, 20, r) } else { ll_ui_set(i, 19, r) }
|
||||
} else { if streq(k, "align") {
|
||||
if v.kind == E_ID {
|
||||
let a = 0
|
||||
var a = 0
|
||||
if streq(v.s, "center") { a = 1 }; if streq(v.s, "end") { a = 2 }
|
||||
ll_ui_set(i, 12, itoa(a))
|
||||
} else { let vv = emit_expr(v); ll_ui_set(i, 12, vv.code) }
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ fn read_file(path: str) -> ptr {
|
|||
|
||||
# length of a NUL-terminated buffer
|
||||
fn cstr_len(s: ptr) -> int {
|
||||
let n = 0
|
||||
var n = 0
|
||||
while peek8(s, n) != 0 { n = n + 1 }
|
||||
return n
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ fn is_op1(c: int) -> bool {
|
|||
|
||||
fn lex(src: ptr) -> void {
|
||||
toks = new []Tok
|
||||
let i = 0
|
||||
let line = 1
|
||||
var i = 0
|
||||
var line = 1
|
||||
let n = slen(src)
|
||||
while i < n {
|
||||
let c = peek8(src, i)
|
||||
|
|
@ -52,11 +52,11 @@ fn lex(src: ptr) -> void {
|
|||
i = i + 1
|
||||
let start = i
|
||||
let out = mem_alloc(n)
|
||||
let j = 0
|
||||
var j = 0
|
||||
while i < n and peek8(src, i) != 34 {
|
||||
if peek8(src, i) == 92 { # backslash escape
|
||||
let e = peek8(src, i + 1)
|
||||
let r = e
|
||||
var r = e
|
||||
if e == 110 { r = 10 }
|
||||
if e == 116 { r = 9 }
|
||||
if e == 48 { r = 0 }
|
||||
|
|
@ -70,7 +70,7 @@ fn lex(src: ptr) -> void {
|
|||
}
|
||||
if c == 39 { # 'c' char literal -> int
|
||||
i = i + 1
|
||||
let v = 0
|
||||
var v = 0
|
||||
if peek8(src, i) == 92 {
|
||||
let e = peek8(src, i + 1)
|
||||
if e == 110 { v = 10 }
|
||||
|
|
@ -84,11 +84,11 @@ fn lex(src: ptr) -> void {
|
|||
}
|
||||
if char_is_digit(c) {
|
||||
if c == 48 and peek8(src, i + 1) == 120 { # 0x hex
|
||||
let v = 0
|
||||
var v = 0
|
||||
i = i + 2
|
||||
while i < n {
|
||||
let h = peek8(src, i)
|
||||
let d = 0
|
||||
var d = 0
|
||||
if char_is_digit(h) { d = h - 48 }
|
||||
else { if h >= 97 and h <= 102 { d = h - 87 }
|
||||
else { if h >= 65 and h <= 70 { d = h - 55 } else { break } } }
|
||||
|
|
@ -98,12 +98,12 @@ fn lex(src: ptr) -> void {
|
|||
tok_push(TK_INT, ptr_null(), v, line)
|
||||
continue
|
||||
}
|
||||
let v = 0
|
||||
var v = 0
|
||||
while i < n and char_is_digit(peek8(src, i)) { v = v * 10 + (peek8(src, i) - 48); i = i + 1 }
|
||||
# a fractional part makes it a Q16.16 fixed literal
|
||||
if i < n and peek8(src, i) == 46 and char_is_digit(peek8(src, i + 1)) {
|
||||
i = i + 1
|
||||
let fnum = 0; let fden = 1
|
||||
var fnum = 0; var fden = 1
|
||||
while i < n and char_is_digit(peek8(src, i)) { fnum = fnum * 10 + (peek8(src, i) - 48); fden = fden * 10; i = i + 1 }
|
||||
let bits = shl(v, 16) + shl(fnum, 16) / fden
|
||||
tok_push(TK_FLOAT, ptr_null(), bits, line)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
# basename: the part of a path after the last '/'.
|
||||
fn base_name(path: ptr) -> ptr {
|
||||
let last = 0 - 1
|
||||
let i = 0
|
||||
var last = 0 - 1
|
||||
var i = 0
|
||||
while peek8(path, i) != 0 { if peek8(path, i) == 47 { last = i }; i = i + 1 }
|
||||
return substr(path, last + 1, i - (last + 1))
|
||||
}
|
||||
|
|
@ -52,18 +52,18 @@ fn die(msg: ptr) -> void {
|
|||
}
|
||||
|
||||
entry {
|
||||
let path = ptr_null()
|
||||
let out = ptr_null()
|
||||
let want = 0 # 0 = auto, 1 = windowed, 2 = headless
|
||||
let emit_ir = false # --emit-llvm: stop after writing IR
|
||||
let fmt = false # --fmt: lex + parse only, then exit (the doc-check gate)
|
||||
let save = false # --save-temps: keep the intermediate .ll
|
||||
let run = false # compile then execute the result
|
||||
var path = ptr_null()
|
||||
var out = ptr_null()
|
||||
var want = 0 # 0 = auto, 1 = windowed, 2 = headless
|
||||
var emit_ir = false # --emit-llvm: stop after writing IR
|
||||
var fmt = false # --fmt: lex + parse only, then exit (the doc-check gate)
|
||||
var save = false # --save-temps: keep the intermediate .ll
|
||||
var run = false # compile then execute the result
|
||||
|
||||
# multi-call: invoked as `ludic` -> run mode by default
|
||||
if streq(base_name(os_arg(0)), "ludic") { run = true }
|
||||
|
||||
let ai = 1
|
||||
var ai = 1
|
||||
while ai < os_argc() {
|
||||
let a = os_arg(ai)
|
||||
if streq(a, "--windowed") { want = 1 }
|
||||
|
|
@ -134,7 +134,7 @@ entry {
|
|||
# platform layer and the Cocoa framework.
|
||||
# -Wno-override-module: our IR carries an explicit target triple, which clang
|
||||
# would otherwise warn about on every build.
|
||||
let cmd = sconcat(cc, sconcat(" -O2 -Wno-override-module ", ll))
|
||||
var cmd = sconcat(cc, sconcat(" -O2 -Wno-override-module ", ll))
|
||||
if g_windowed {
|
||||
let cocoa = path_join(home, "runtime/native/cocoa.ll")
|
||||
cmd = sconcat(cmd, sconcat(" ", sconcat(cocoa, " -framework Cocoa -Wl,-rpath,@loader_path")))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# parse.ludic — recursive-descent parser: the token slice -> an AST.
|
||||
# Reduced grammar: structs, vars, consts, fns, main; no ECS/scene/ui/match.
|
||||
# Mirrors compiler/front/parse.c. Uses the global `toks` and a cursor `pi`.
|
||||
# Core grammar: properties, vars/lets, consts, fns, entry; the ECS/ui/match
|
||||
# constructs live in parse_game.ludic. Uses the global `toks` and a cursor `pi`.
|
||||
|
||||
var pi: int = 0
|
||||
var prog: []Node # the top-level declarations
|
||||
|
|
@ -37,7 +37,7 @@ fn ptype() -> ptr {
|
|||
let el = ptype()
|
||||
let out = mem_alloc(slen(el) + 3)
|
||||
poke8(out, 0, 91); poke8(out, 1, 93) # "[]"
|
||||
let i = 0
|
||||
var i = 0
|
||||
while peek8(el, i) != 0 { poke8(out, 2 + i, peek8(el, i)); i = i + 1 }
|
||||
poke8(out, 2 + i, 0)
|
||||
return out
|
||||
|
|
@ -71,7 +71,7 @@ fn p_primary() -> Node {
|
|||
}
|
||||
|
||||
fn p_postfix() -> Node {
|
||||
let e = p_primary()
|
||||
var e = p_primary()
|
||||
while true {
|
||||
if is_op(".") { pi = pi + 1; let m = node(E_MEMBER); m.a = e; m.s = eat_id(); e = m }
|
||||
else { if is_op("[") { pi = pi + 1; let ix = node(E_INDEX); ix.a = e; ix.b = expr(); eat_op("]"); e = ix }
|
||||
|
|
@ -89,29 +89,29 @@ fn p_unary() -> Node {
|
|||
fn mkbin(op: ptr, l: Node, r: Node) -> Node { let b = node(E_BIN); b.s = op; b.a = l; b.b = r; return b }
|
||||
|
||||
fn p_mul() -> Node {
|
||||
let l = p_unary()
|
||||
var l = p_unary()
|
||||
while is_op("*") or is_op("/") or is_op("%") { let op = toks[pi].text; pi = pi + 1; l = mkbin(op, l, p_unary()) }
|
||||
return l
|
||||
}
|
||||
fn p_add() -> Node {
|
||||
let l = p_mul()
|
||||
var l = p_mul()
|
||||
while is_op("+") or is_op("-") { let op = toks[pi].text; pi = pi + 1; l = mkbin(op, l, p_mul()) }
|
||||
return l
|
||||
}
|
||||
fn p_cmp() -> Node {
|
||||
let l = p_add()
|
||||
var l = p_add()
|
||||
while is_op("<") or is_op("<=") or is_op(">") or is_op(">=") or is_op("==") or is_op("!=") {
|
||||
let op = toks[pi].text; pi = pi + 1; l = mkbin(op, l, p_add())
|
||||
}
|
||||
return l
|
||||
}
|
||||
fn p_and() -> Node {
|
||||
let l = p_cmp()
|
||||
var l = p_cmp()
|
||||
while is_id("and") { pi = pi + 1; l = mkbin("and", l, p_cmp()) }
|
||||
return l
|
||||
}
|
||||
fn p_or() -> Node {
|
||||
let l = p_and()
|
||||
var l = p_and()
|
||||
while is_id("or") { pi = pi + 1; l = mkbin("or", l, p_and()) }
|
||||
return l
|
||||
}
|
||||
|
|
@ -136,14 +136,9 @@ fn block() -> Node {
|
|||
# Rule B: statements are separated by a newline or ';' (both lex to TK_NL).
|
||||
# After a statement the next token must be that separator or the block's end —
|
||||
# two statements may not sit adjacent with only spaces between them.
|
||||
let sep = toks[pi].kind == TK_NL
|
||||
var sep = toks[pi].kind == TK_NL
|
||||
if is_op("}") { sep = true }
|
||||
if not sep {
|
||||
let ez = file_stderr(); file_write(ez, "cur=", 4)
|
||||
if not ptr_is_null(toks[pi].text) { file_write(ez, toks[pi].text, slen(toks[pi].text)) }
|
||||
file_write(ez, "\n", 1); print_int(7770000 + toks[pi].line)
|
||||
perr("expected newline or ';' between statements")
|
||||
}
|
||||
if not sep { perr("expected newline or ';' between statements") }
|
||||
}
|
||||
eat_op("}")
|
||||
return b
|
||||
|
|
@ -152,8 +147,9 @@ fn block() -> Node {
|
|||
fn stmt() -> Node {
|
||||
let t = toks[pi]
|
||||
if t.kind == TK_ID {
|
||||
if streq(t.text, "let") {
|
||||
pi = pi + 1; let n = node(S_LET); n.s = eat_id()
|
||||
if streq(t.text, "let") or streq(t.text, "var") {
|
||||
var mut = 0; if streq(t.text, "var") { mut = 1 } # let = immutable, var = mutable
|
||||
pi = pi + 1; let n = node(S_LET); n.ival = mut; n.line = toks[pi].line; n.s = eat_id()
|
||||
if is_op(":") { pi = pi + 1; n.ty = ptype() }
|
||||
if is_op("=") { pi = pi + 1; n.a = expr() }
|
||||
return n
|
||||
|
|
@ -183,7 +179,7 @@ fn stmt() -> Node {
|
|||
if streq(t.text, "spawn") { return parse_spawn() }
|
||||
if streq(t.text, "machine") {
|
||||
pi = pi + 1; let n = node(S_MACHINE); n.a = expr(); skipnl(); eat_op("{")
|
||||
let sidx = 0 # states auto-number by declaration order
|
||||
var sidx = 0 # states auto-number by declaration order
|
||||
while true { skipnl(); if is_op("}") { break }
|
||||
let stkw = eat_id() # 'state'
|
||||
let s = node(S_STATE); s.s = eat_id()
|
||||
|
|
@ -196,7 +192,7 @@ fn stmt() -> Node {
|
|||
if streq(t.text, "become") { pi = pi + 1; let n = node(S_BECOME); n.s = eat_id(); return n }
|
||||
if streq(t.text, "despawn") { pi = pi + 1; let n = node(S_DESPAWN); n.a = expr(); return n }
|
||||
if streq(t.text, "enable") or streq(t.text, "disable") {
|
||||
let en = 0; if streq(t.text, "enable") { en = 1 }
|
||||
var en = 0; if streq(t.text, "enable") { en = 1 }
|
||||
pi = pi + 1; let n = node(S_TOGGLE); n.ival = en; n.s = eat_id() # `enable P on e` / `disable Model` / `disable Handler`
|
||||
if is_id("on") { pi = pi + 1; n.a = expr() } # property on an entity
|
||||
return n
|
||||
|
|
@ -218,7 +214,7 @@ fn stmt() -> Node {
|
|||
}
|
||||
let e = expr()
|
||||
if is_op("=") or is_op("+=") or is_op("-=") or is_op("*=") or is_op("/=") {
|
||||
let n = node(S_ASSIGN); n.s = toks[pi].text; pi = pi + 1; n.a = e; n.b = expr(); return n
|
||||
let n = node(S_ASSIGN); n.line = toks[pi].line; n.s = toks[pi].text; pi = pi + 1; n.a = e; n.b = expr(); return n
|
||||
}
|
||||
let n = node(S_EXPR); n.a = e; return n
|
||||
}
|
||||
|
|
@ -249,8 +245,8 @@ fn parse_main() -> Node { pi = pi + 1; let n = node(N_MAIN); n.a = block(); retu
|
|||
|
||||
# directory part of a path, including the trailing '/', or "" if none
|
||||
fn dir_of(path: ptr) -> ptr {
|
||||
let last = 0 - 1
|
||||
let i = 0
|
||||
var last = 0 - 1
|
||||
var i = 0
|
||||
while peek8(path, i) != 0 { if peek8(path, i) == 47 { last = i }; i = i + 1 }
|
||||
if last < 0 { return "" }
|
||||
return substr(path, 0, last + 1)
|
||||
|
|
@ -264,7 +260,7 @@ var loaded_paths: []ptr
|
|||
var cur_dir: ptr
|
||||
|
||||
fn already_loaded(full: ptr) -> bool {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < len(loaded_paths) { if streq(loaded_paths[i], full) { return true }; i = i + 1 }
|
||||
return false
|
||||
}
|
||||
|
|
@ -273,14 +269,14 @@ fn already_loaded(full: ptr) -> bool {
|
|||
# Modifiers are `@annotations` in front of the declaration: `@export`, `@edge`,
|
||||
# `@pure`, `@deterministic`, … — one channel, not a zoo of prefix keywords.
|
||||
fn parse_one_decl() -> void {
|
||||
let is_export = false
|
||||
let qspec: Node = ptr_null()
|
||||
let onspawn_model: ptr = ptr_null()
|
||||
let ondespawn_model: ptr = ptr_null()
|
||||
let onattach_prop: ptr = ptr_null()
|
||||
let onenable_prop: ptr = ptr_null()
|
||||
let ondisable_prop: ptr = ptr_null()
|
||||
let hook_phase: ptr = ptr_null() # @OnStart / @OnQuit override the phase
|
||||
var is_export = false
|
||||
var qspec: Node = ptr_null()
|
||||
var onspawn_model: ptr = ptr_null()
|
||||
var ondespawn_model: ptr = ptr_null()
|
||||
var onattach_prop: ptr = ptr_null()
|
||||
var onenable_prop: ptr = ptr_null()
|
||||
var ondisable_prop: ptr = ptr_null()
|
||||
var hook_phase: ptr = ptr_null() # @OnStart / @OnQuit override the phase
|
||||
while is_op("@") {
|
||||
pi = pi + 1; let a = eat_id() # collect a leading @annotation
|
||||
if streq(a, "export") { is_export = true }
|
||||
|
|
@ -292,7 +288,7 @@ fn parse_one_decl() -> void {
|
|||
else { if streq(a, "OnDisable") { eat_op("("); ondisable_prop = eat_id(); eat_op(")") }
|
||||
else { if streq(a, "OnStart") { hook_phase = "Start" } # boot
|
||||
else { if streq(a, "OnQuit") { hook_phase = "OnQuit" } # shutdown
|
||||
else { if is_op("(") { let d = 0 # any other @anno(args) — parsed and skipped
|
||||
else { if is_op("(") { var d = 0 # any other @anno(args) — parsed and skipped
|
||||
while true { if is_op("(") { d = d + 1 }; if is_op(")") { d = d - 1 }; pi = pi + 1; if d == 0 { break } } } } } } } } } } } }
|
||||
skipnl()
|
||||
}
|
||||
|
|
@ -371,7 +367,7 @@ fn parse_program() -> void {
|
|||
# @annotations on the program itself (e.g. @Handles(Movement)) — parsed, skipped
|
||||
while is_op("@") {
|
||||
pi = pi + 1; let a = eat_id()
|
||||
if is_op("(") { let d = 0
|
||||
if is_op("(") { var d = 0
|
||||
while true { if is_op("(") { d = d + 1 }; if is_op(")") { d = d - 1 }; pi = pi + 1; if d == 0 { break } } }
|
||||
skipnl()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
fn parse_component() -> Node {
|
||||
pi = pi + 1; let n = node(N_COMP); n.s = eat_id(); skipnl(); eat_op("{")
|
||||
while true { skipnl(); if is_op("}") { break }
|
||||
let is_computed = false
|
||||
var is_computed = false
|
||||
if is_op("@") { pi = pi + 1; let ann = eat_id(); if streq(ann, "Computed") { is_computed = true }; skipnl() }
|
||||
let f = node(N_FIELD); f.s = eat_id(); eat_op(":"); f.ty = ptype()
|
||||
if is_op("=") { pi = pi + 1; f.a = expr() }
|
||||
|
|
@ -23,7 +23,7 @@ fn parse_system() -> Node {
|
|||
# in a signature clause.
|
||||
while true {
|
||||
skipnl() # clauses may span several lines
|
||||
if is_op("@") { pi = pi + 1; let a = eat_id(); if is_op("(") { let d = 0 # @anno, one per turn so a
|
||||
if is_op("@") { pi = pi + 1; let a = eat_id(); if is_op("(") { var d = 0 # @anno, one per turn so a
|
||||
while true { if is_op("(") { d = d + 1 }; if is_op(")") { d = d - 1 }; pi = pi + 1; if d == 0 { break } } }
|
||||
continue } # newline-separated @anno re-skips at the loop top
|
||||
if is_id("phase") { pi = pi + 1; n.ty = eat_id(); continue }
|
||||
|
|
@ -99,7 +99,7 @@ fn parse_queries_anno() -> Node {
|
|||
eat_op("(")
|
||||
let qn = node(S_QUERY)
|
||||
let terms = node(N_BLOCK)
|
||||
let wh: Node = ptr_null()
|
||||
var wh: Node = ptr_null()
|
||||
while not is_op(")") {
|
||||
skipnl()
|
||||
if is_op(")") { break }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# byte buffers reached with peek8/poke8.
|
||||
|
||||
fn streq(a: ptr, b: ptr) -> bool {
|
||||
let i = 0
|
||||
var i = 0
|
||||
while true {
|
||||
let ca = peek8(a, i)
|
||||
let cb = peek8(b, i)
|
||||
|
|
@ -15,7 +15,7 @@ fn streq(a: ptr, b: ptr) -> bool {
|
|||
}
|
||||
|
||||
fn slen(s: ptr) -> int {
|
||||
let n = 0
|
||||
var n = 0
|
||||
while peek8(s, n) != 0 { n = n + 1 }
|
||||
return n
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ fn slen(s: ptr) -> int {
|
|||
# a fresh NUL-terminated copy of src[start .. start+n]
|
||||
fn substr(src: ptr, start: int, n: int) -> ptr {
|
||||
let b = mem_alloc(n + 1)
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < n { poke8(b, i, peek8(src, start + i)); i = i + 1 }
|
||||
poke8(b, n, 0)
|
||||
return b
|
||||
|
|
@ -40,18 +40,18 @@ fn char_is_alnum(c: int) -> bool { return char_is_alpha(c) or char_is_digit(c) }
|
|||
# integer -> fresh decimal string
|
||||
fn itoa(v: int) -> ptr {
|
||||
if v == 0 { let z = mem_alloc(2); poke8(z, 0, 48); poke8(z, 1, 0); return z }
|
||||
let neg = false
|
||||
let x = v
|
||||
var neg = false
|
||||
var x = v
|
||||
if x < 0 { neg = true; x = 0 - x }
|
||||
let tmp = mem_alloc(16)
|
||||
let n = 0
|
||||
var n = 0
|
||||
while x > 0 { poke8(tmp, n, 48 + x % 10); x = x / 10; n = n + 1 }
|
||||
let total = n
|
||||
var total = n
|
||||
if neg { total = total + 1 }
|
||||
let out = mem_alloc(total + 1)
|
||||
let k = 0
|
||||
var k = 0
|
||||
if neg { poke8(out, 0, 45); k = 1 }
|
||||
let i = 0
|
||||
var i = 0
|
||||
while i < n { poke8(out, k + i, peek8(tmp, n - 1 - i)); i = i + 1 }
|
||||
poke8(out, total, 0)
|
||||
return out
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ program T {
|
|||
fn fib(n: int) -> int { if n < 2 { return n }; return fib(n-1) + fib(n-2) }
|
||||
entry {
|
||||
print_int(fib(10)) # 55
|
||||
let s = 0
|
||||
var s = 0
|
||||
for i in 0 .. 10 { if i == 5 { break }; if i % 2 == 0 { continue }; s = s + i }
|
||||
print_int(s) # 1+3 = 4
|
||||
let i = 0; let t = 0
|
||||
var i = 0; var t = 0
|
||||
while true { i = i + 1; if i > 5 { break }; t = t + i }
|
||||
print_int(t) # 15
|
||||
if false and (1/0 == 0) { print_int(999) } else { print_int(1) } # short-circuit: no div by zero
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue