feat(types): Huge + Angle + Percent polish numeric types (#55)
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:
parent
539f258d92
commit
5dc8394f22
33 changed files with 23162 additions and 21092 deletions
7
docs/language/angle/_section.md
Normal file
7
docs/language/angle/_section.md
Normal 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>.
|
||||
22
docs/language/angle/angle-add.md
Normal file
22
docs/language/angle/angle-add.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-cos.md
Normal file
22
docs/language/angle/angle-cos.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-diff.md
Normal file
22
docs/language/angle/angle-diff.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-from_degrees.md
Normal file
22
docs/language/angle/angle-from_degrees.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-lerp.md
Normal file
22
docs/language/angle/angle-lerp.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-sin.md
Normal file
22
docs/language/angle/angle-sin.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-to_degrees.md
Normal file
22
docs/language/angle/angle-to_degrees.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/angle/angle-wrap.md
Normal file
22
docs/language/angle/angle-wrap.md
Normal 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)
|
||||
}
|
||||
}
|
||||
```
|
||||
7
docs/language/huge/_section.md
Normal file
7
docs/language/huge/_section.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
id: huge
|
||||
title: Huge
|
||||
order: 14
|
||||
---
|
||||
|
||||
Idle/incremental big numbers — magnitudes far past what a 32- or 64-bit integer can hold, for prestige currencies and exponential growth. A <code>Huge</code> is a normalized mantissa (a Q16.16 <code>fixed</code> in [1, 10)) times <code>10^exponent</code>, so it can represent 10^100 or 10^1000 while staying one small value. It is a <strong>display-scale</strong> number (about four significant digits), <em>not</em> a lockstep-exact one — keep it out of the deterministic simulation and reach for <code>BigInt</code> / <code>Decimal</code> when exactness matters. Build one with <code>Huge.from</code>, combine with <code>add</code> / <code>sub</code> / <code>mul</code> / <code>neg</code>, compare with <code>cmp</code> / <code>sign</code>, read <code>mantissa</code> / <code>exp</code>, and render as <code>1.23e45</code> with <code>str</code>. Arguments are positional. Spliced in only when a program mentions <code>Huge.*</code>.
|
||||
22
docs/language/huge/huge-add.md
Normal file
22
docs/language/huge/huge-add.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-add
|
||||
name: Huge.add
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.add
|
||||
sig: Huge.add(a, b) -> Huge
|
||||
tip: Sum of two big numbers.
|
||||
order: 1
|
||||
ns: Huge
|
||||
member: add
|
||||
---
|
||||
|
||||
Adds two big numbers, aligning their exponents; a term too small to matter at display precision is dropped.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
gold = Huge.add(gold, income)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-cmp.md
Normal file
22
docs/language/huge/huge-cmp.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-cmp
|
||||
name: Huge.cmp
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.cmp
|
||||
sig: Huge.cmp(a, b) -> int
|
||||
tip: Compare two big numbers: -1, 0, or 1.
|
||||
order: 5
|
||||
ns: Huge
|
||||
member: cmp
|
||||
---
|
||||
|
||||
Compares two big numbers, returning <code>-1</code>, <code>0</code>, or <code>1</code> as <code>a</code> is less than, equal to, or greater than <code>b</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
if Huge.cmp(gold, price) >= 0 { buy() }
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-exp.md
Normal file
22
docs/language/huge/huge-exp.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-exp
|
||||
name: Huge.exp
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.exp
|
||||
sig: Huge.exp(a) -> int
|
||||
tip: The base-10 exponent.
|
||||
order: 8
|
||||
ns: Huge
|
||||
member: exp
|
||||
---
|
||||
|
||||
Returns the base-10 exponent — how many orders of magnitude the value spans.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let order = Huge.exp(gold)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-from.md
Normal file
22
docs/language/huge/huge-from.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-from
|
||||
name: Huge.from
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.from
|
||||
sig: Huge.from(value) -> Huge
|
||||
tip: Turn an int into a Huge.
|
||||
order: 0
|
||||
ns: Huge
|
||||
member: from
|
||||
---
|
||||
|
||||
Lifts a plain <code>int</code> into a <code>Huge</code>, the starting point for idle-game magnitudes that grow past the integer range.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
var gold = Huge.from(1000)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-mantissa.md
Normal file
22
docs/language/huge/huge-mantissa.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-mantissa
|
||||
name: Huge.mantissa
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.mantissa
|
||||
sig: Huge.mantissa(a) -> fixed
|
||||
tip: The mantissa in [1, 10).
|
||||
order: 7
|
||||
ns: Huge
|
||||
member: mantissa
|
||||
---
|
||||
|
||||
Returns the normalized mantissa, a <code>fixed</code> in [1, 10) (or 0). Pair it with <code>Huge.exp</code> to format a value your own way.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let m = Huge.mantissa(gold)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-mul.md
Normal file
22
docs/language/huge/huge-mul.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-mul
|
||||
name: Huge.mul
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.mul
|
||||
sig: Huge.mul(a, b) -> Huge
|
||||
tip: Product of two big numbers.
|
||||
order: 3
|
||||
ns: Huge
|
||||
member: mul
|
||||
---
|
||||
|
||||
Multiplies two big numbers (mantissas multiply, exponents add) — the exponential growth step at the heart of an idle game.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
gold = Huge.mul(gold, multiplier)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-neg.md
Normal file
22
docs/language/huge/huge-neg.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-neg
|
||||
name: Huge.neg
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.neg
|
||||
sig: Huge.neg(a) -> Huge
|
||||
tip: Negate a big number.
|
||||
order: 4
|
||||
ns: Huge
|
||||
member: neg
|
||||
---
|
||||
|
||||
Returns <code>-a</code>, the same magnitude with the opposite sign.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let owed = Huge.neg(balance)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-sign.md
Normal file
22
docs/language/huge/huge-sign.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-sign
|
||||
name: Huge.sign
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.sign
|
||||
sig: Huge.sign(a) -> int
|
||||
tip: The sign: -1, 0, or 1.
|
||||
order: 6
|
||||
ns: Huge
|
||||
member: sign
|
||||
---
|
||||
|
||||
Returns the sign of the value: <code>-1</code>, <code>0</code>, or <code>1</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
if Huge.sign(balance) < 0 { warn() }
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-str.md
Normal file
22
docs/language/huge/huge-str.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-str
|
||||
name: Huge.str
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.str
|
||||
sig: Huge.str(a) -> string
|
||||
tip: Render as scientific text like 1.23e45.
|
||||
order: 9
|
||||
ns: Huge
|
||||
member: str
|
||||
---
|
||||
|
||||
Renders the value in scientific form, like <code>1.23e45</code> (a two-decimal mantissa). This is how you show an idle magnitude on the HUD.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
Screen.draw_text(8, 8, Huge.str(gold), Color.White, 1)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/huge/huge-sub.md
Normal file
22
docs/language/huge/huge-sub.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: huge-sub
|
||||
name: Huge.sub
|
||||
category: huge
|
||||
kind: namespace-method
|
||||
tokens: Huge.sub
|
||||
sig: Huge.sub(a, b) -> Huge
|
||||
tip: Difference of two big numbers.
|
||||
order: 2
|
||||
ns: Huge
|
||||
member: sub
|
||||
---
|
||||
|
||||
Subtracts <code>b</code> from <code>a</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
gold = Huge.sub(gold, cost)
|
||||
}
|
||||
}
|
||||
```
|
||||
7
docs/language/percent/_section.md
Normal file
7
docs/language/percent/_section.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
id: percent
|
||||
title: Percent
|
||||
order: 16
|
||||
---
|
||||
|
||||
A value clamped to <code>[0, 1]</code> — health fractions, volumes, and the <code>t</code> of an interpolation, without stray values slipping below 0 or above 1. <code>Percent.clamp</code> pins any <code>fixed</code> into range; <code>Percent.of</code> forms a clamped ratio <code>num / den</code>; <code>Percent.lerp</code> interpolates <code>a..b</code> by a clamped <code>t</code>; and <code>Percent.apply</code> scales a value by a clamped fraction. Every operation is deterministic fixed-point. Arguments are positional. Spliced in only when a program mentions <code>Percent.*</code>.
|
||||
22
docs/language/percent/percent-apply.md
Normal file
22
docs/language/percent/percent-apply.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: percent-apply
|
||||
name: Percent.apply
|
||||
category: percent
|
||||
kind: namespace-method
|
||||
tokens: Percent.apply
|
||||
sig: Percent.apply(value, p) -> fixed
|
||||
tip: Scale a value by a clamped percent.
|
||||
order: 3
|
||||
ns: Percent
|
||||
member: apply
|
||||
---
|
||||
|
||||
Scales <code>value</code> by a clamped fraction <code>p</code> — for example, applying a damage-reduction percentage.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let dealt = Percent.apply(damage, 0.75)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/percent/percent-clamp.md
Normal file
22
docs/language/percent/percent-clamp.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: percent-clamp
|
||||
name: Percent.clamp
|
||||
category: percent
|
||||
kind: namespace-method
|
||||
tokens: Percent.clamp
|
||||
sig: Percent.clamp(v) -> fixed
|
||||
tip: Clamp any fixed into [0, 1].
|
||||
order: 0
|
||||
ns: Percent
|
||||
member: clamp
|
||||
---
|
||||
|
||||
Pins any <code>fixed</code> into the range [0, 1] — a health fraction or volume that can never slip out of bounds.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let hp = Percent.clamp(health)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/percent/percent-lerp.md
Normal file
22
docs/language/percent/percent-lerp.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: percent-lerp
|
||||
name: Percent.lerp
|
||||
category: percent
|
||||
kind: namespace-method
|
||||
tokens: Percent.lerp
|
||||
sig: Percent.lerp(a, b, t) -> fixed
|
||||
tip: Interpolate a..b by a clamped t.
|
||||
order: 2
|
||||
ns: Percent
|
||||
member: lerp
|
||||
---
|
||||
|
||||
Interpolates from <code>a</code> to <code>b</code> by <code>t</code>, clamping <code>t</code> to [0, 1] first so the result never overshoots the endpoints.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let x = Percent.lerp(startX, endX, progress)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/percent/percent-of.md
Normal file
22
docs/language/percent/percent-of.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: percent-of
|
||||
name: Percent.of
|
||||
category: percent
|
||||
kind: namespace-method
|
||||
tokens: Percent.of
|
||||
sig: Percent.of(num, den) -> fixed
|
||||
tip: Clamped ratio num / den.
|
||||
order: 1
|
||||
ns: Percent
|
||||
member: of
|
||||
---
|
||||
|
||||
Forms the ratio <code>num / den</code> clamped to [0, 1] (0 when <code>den</code> is 0) — a filled-fraction from a part and a whole.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let filled = Percent.of(current, maximum)
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue