prometeu-runtime/docs/pull-requests/PR-003-runtime-first-builtins-color-vec2-pixel.md
2026-03-24 13:40:45 +00:00

5.3 KiB

PR-003 Runtime First Builtins: Color, Vec2, Pixel

Goal

Implement the first concrete builtin types, constants, and intrinsic behaviors so the frontend can target a stable MVP builtin line.

This PR should be the first runtime feature slice that a PBS frontend can map to directly.

Why

After PR-001 and PR-002, the runtime has the machinery but not the domain set. This PR makes the model real by installing the first builtin registry entries and execution implementations.

The initial scope should match the current agenda and spec direction:

  • scalar builtin color
  • aggregate builtin vec2
  • aggregate builtin pixel
  • intrinsic methods for vec2
  • builtin constant for vec2.zero

Scope

Add runtime registry entries and implementations for:

  • builtin type color
  • builtin type vec2
  • builtin type pixel
  • builtin constant ("vec2", "zero", 1)
  • intrinsic ("vec2", "dot", 1)
  • intrinsic ("vec2", "length", 1)

("vec2", "distance", 1) may be included if the numeric contract is already clear enough for portable behavior. If not, leave it for a follow-up PR.

Builtin Type Contracts

1. color

Canonical identity:

("color", 1)

Expected properties:

  • scalar builtin
  • flat slot width 1
  • runtime semantic distinctness from plain int

Suggested field model:

  • raw carrier field if the runtime benefits from explicit internal naming

2. vec2

Canonical identity:

("vec2", 1)

Expected properties:

  • aggregate builtin
  • flattened layout [float, float]
  • field x at slot 0
  • field y at slot 1
  • flat slot width 2

3. pixel

Canonical identity:

("pixel", 1)

Expected properties:

  • aggregate builtin
  • semantic layout [int, int, color]
  • flattened width 3
  • field x at slot 0
  • field y at slot 1
  • field color at slot 2

Builtin Constant Contract

vec2.zero

Canonical identity:

("vec2", "zero", 1)

Expected materialized value:

[0.0, 0.0]

This constant must be runtime-owned and materialized without touching the host.

Intrinsic Contracts

1. vec2.dot

Canonical identity:

("vec2", "dot", 1)

Stack contract:

args: [float, float, float, float]
ret:  [float]

Semantic behavior:

(x1 * x2) + (y1 * y2)

2. vec2.length

Canonical identity:

("vec2", "length", 1)

Stack contract:

args: [float, float]
ret:  [float]

Semantic behavior:

sqrt((x * x) + (y * y))

3. Optional: vec2.distance

Canonical identity:

("vec2", "distance", 1)

Stack contract:

args: [float, float, float, float]
ret:  [float]

Semantic behavior:

sqrt(((x1 - x2)^2) + ((y1 - y2)^2))

Only include this if the runtime already has a clear portable numeric contract for sqrt.

Representation Guidance

color

Choose one of:

  1. dedicated scalar runtime variant with builtin nominal tag
  2. 1-slot scalar carrier plus explicit builtin registry identity

The critical rule is:

  • color must remain semantically a builtin color type,
  • even if its carrier width matches int.

vec2 and pixel

Do not allocate heap objects for these in the MVP.

Represent them as:

  • canonical stack-shaped flattened values,
  • with runtime metadata describing field offsets and nominal builtin identity.

Numeric Contract Note

vec2.dot is straightforward and should land in this PR.

vec2.length and vec2.distance depend on the runtime's floating-point portability story. If that story is not already stable, implement:

  1. vec2.dot
  2. vec2.zero
  3. builtin type descriptors for color, vec2, pixel

and either:

  • gate length/distance behind the current platform float rules,
  • or defer them into a follow-up PR.

Acceptance Criteria

  1. Runtime registry contains builtin entries for color, vec2, and pixel.
  2. Runtime registry contains builtin constant entry for ("vec2", "zero", 1).
  3. Runtime registry contains intrinsic entries for at least vec2.dot and vec2.length.
  4. vec2 layout is width 2 and pixel layout is width 3.
  5. pixel composes color through builtin layout metadata rather than by special-case host code.
  6. Executing vec2.dot and vec2.length through INTRINSIC <id> produces correct runtime results.
  7. No part of the implementation routes through SYSC, HOSTCALL, or SYSCALL.

Test Cases

Builtin metadata

  • color width is 1
  • vec2 width is 2
  • pixel width is 3

Constant materialization

  • materializing ("vec2", "zero", 1) yields [0.0, 0.0]

Intrinsic execution

  • dot([1, 2], [3, 4]) == 11
  • length([3, 4]) == 5

Composition

  • pixel(x=1, y=2, color=<red>) uses builtin metadata width 3
  • pixel.color points at slot 2

Frontend Alignment

This PR should be implemented so the following frontend surfaces map naturally:

[BuiltinType(name="vec2", version=1)]
declare builtin type Vec2(
    [Slot(0)] pub x: float,
    [Slot(1)] pub y: float,
) {
    [IntrinsicCall(name="dot")]
    fn dot(other: Vec2) -> float;

    [IntrinsicCall(name="length")]
    fn length() -> float;
}

[BuiltinConst(target="vec2", name="zero", version=1)]
declare const ZERO: Vec2;

The runtime should not care whether the source-visible type name is Vec2, vec2, or something else. It should care only about canonical identities and flattened layout.