feat(types): Huge + Angle + Percent polish numeric types (#55)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 19s
ci / build-and-test (push) Successful in 1m30s
commit-lint / conventional-commits (push) Successful in 6s
docs / build-and-deploy (push) Successful in 23s

Types phase 5 (polish). A splice-on-demand numeric runtime
(runtime/native/numeric.ludic, built on the inline Math.* trig) behind three
namespaces:

- Huge.* — idle big numbers (normalized mantissa x 10^exponent): from/add/
  sub/mul/neg/cmp/sign/mantissa/exp/str (scientific 1.23e45). Display-scale,
  not lockstep-exact (BigInt/Decimal for exactness).
- Angle.* — auto-wrapping radians: from_degrees/to_degrees/wrap/sin/cos/add/
  diff (shortest signed rotation)/lerp (shortest arc).
- Percent.* — clamped [0,1]: clamp/of/lerp/apply.

Remaining phase-5 items are already covered (duration=Duration.*,
rune=Unicode.*, i64=long) or need a type-checking pass (handle, typed name,
other sized ints) — tracked for later.

Wired: parser splice trigger (g_uses_numeric), emit_call dispatch, reseeded
seed, a self-asserting example (examples/library/numeric.ludic + feat_case),
per-symbol docs + inventory. All suites green incl. golden renders byte-
identical and the bootstrap fixpoint.

NOTE: fixed `const`s lower to raw-int-typed values (emit_call N_CONST), which
breaks fixed comparisons — the runtime uses inline fixed literals instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-31 19:04:37 +03:00
parent 539f258d92
commit 5dc8394f22
33 changed files with 23162 additions and 21092 deletions

View file

@ -0,0 +1,7 @@
---
id: angle
title: Angle
order: 15
---
An auto-wrapping angle in radians, so you never juggle <code>% TAU</code> by hand. Every <code>Angle.*</code> result is normalized into <code>[-pi, pi)</code>, which makes <code>diff</code> the shortest signed rotation between two headings and <code>lerp</code> turn the short way around. Build from degrees with <code>Angle.from_degrees</code> (read back with <code>to_degrees</code>), take <code>sin</code> / <code>cos</code>, combine with <code>add</code>, and normalize any raw value with <code>wrap</code>. It builds on the deterministic fixed-point <code>Math.*</code> trig, so results are bit-identical on every platform. Arguments are positional; angles are <code>fixed</code> radians. Spliced in only when a program mentions <code>Angle.*</code>.

View file

@ -0,0 +1,22 @@
---
id: angle-add
name: Angle.add
category: angle
kind: namespace-method
tokens: Angle.add
sig: Angle.add(a, b) -> fixed
tip: Add two angles (wrapped).
order: 5
ns: Angle
member: add
---
Adds two angles and wraps the result back into range.
```ludic
program Demo {
handler Step phase Update {
facing = Angle.add(facing, turnRate)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-cos
name: Angle.cos
category: angle
kind: namespace-method
tokens: Angle.cos
sig: Angle.cos(a) -> fixed
tip: Cosine of an angle.
order: 4
ns: Angle
member: cos
---
Returns the cosine of the angle, using the deterministic fixed-point trig.
```ludic
program Demo {
handler Step phase Update {
let dx = Angle.cos(facing)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-diff
name: Angle.diff
category: angle
kind: namespace-method
tokens: Angle.diff
sig: Angle.diff(a, b) -> fixed
tip: Shortest signed rotation from a to b.
order: 6
ns: Angle
member: diff
---
Returns the shortest signed rotation from <code>a</code> to <code>b</code>, in [-pi, pi) — positive to turn one way, negative the other.
```ludic
program Demo {
handler Step phase Update {
let steer = Angle.diff(facing, target)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-from_degrees
name: Angle.from_degrees
category: angle
kind: namespace-method
tokens: Angle.from_degrees
sig: Angle.from_degrees(d) -> fixed
tip: Degrees to a wrapped radian angle.
order: 0
ns: Angle
member: from_degrees
---
Converts degrees to radians and wraps the result into [-pi, pi). The natural way to author a heading a designer types in degrees.
```ludic
program Demo {
handler Step phase Update {
let facing = Angle.from_degrees(90.0)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-lerp
name: Angle.lerp
category: angle
kind: namespace-method
tokens: Angle.lerp
sig: Angle.lerp(a, b, t) -> fixed
tip: Interpolate along the shortest arc.
order: 7
ns: Angle
member: lerp
---
Interpolates from <code>a</code> toward <code>b</code> along the shortest arc (t is a fixed 0..1), so a turn never spins the long way around.
```ludic
program Demo {
handler Step phase Update {
facing = Angle.lerp(facing, target, 0.1)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-sin
name: Angle.sin
category: angle
kind: namespace-method
tokens: Angle.sin
sig: Angle.sin(a) -> fixed
tip: Sine of an angle.
order: 3
ns: Angle
member: sin
---
Returns the sine of the angle, using the deterministic fixed-point trig.
```ludic
program Demo {
handler Step phase Update {
let dy = Angle.sin(facing)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-to_degrees
name: Angle.to_degrees
category: angle
kind: namespace-method
tokens: Angle.to_degrees
sig: Angle.to_degrees(a) -> fixed
tip: Radians back to degrees.
order: 1
ns: Angle
member: to_degrees
---
Converts a radian angle back to degrees — handy for display or debugging.
```ludic
program Demo {
handler Step phase Update {
let deg = Angle.to_degrees(facing)
}
}
```

View file

@ -0,0 +1,22 @@
---
id: angle-wrap
name: Angle.wrap
category: angle
kind: namespace-method
tokens: Angle.wrap
sig: Angle.wrap(a) -> fixed
tip: Normalize any radian value to [-pi, pi).
order: 2
ns: Angle
member: wrap
---
Normalizes any radian value into [-pi, pi), so accumulated rotation never runs away.
```ludic
program Demo {
handler Step phase Update {
heading = Angle.wrap(heading + spin)
}
}
```