enum, union
This commit is contained in:
126
specs.md
126
specs.md
@@ -48,6 +48,8 @@ GLSL;
|
||||
### Keywords
|
||||
`if`, `else`, `then`, `while`, `break`, `continue`, `true`, `false`, `enum`, `struct`, `union`, `case`, `return`, `defer`, `xx`, `and`, `or`
|
||||
|
||||
> Note: `enum` is used for both payload-less and payload-bearing sum types (tagged unions). `union` is reserved for C-style untagged unions (memory overlays).
|
||||
|
||||
### Operators
|
||||
|
||||
| Operator | Meaning |
|
||||
@@ -102,15 +104,88 @@ GLSL;
|
||||
- `Type` — compile-time type value. At runtime, represented as an `i64` type tag (same tag space as `Any`).
|
||||
|
||||
### Enum Types
|
||||
User-defined sum types with named variants.
|
||||
User-defined sum types with named variants. Variants may optionally carry typed data (tagged unions). Internally, payload-less enums are represented as `i64` (variant index). Enums with payloads are represented as `{ i64, [max_payload_size x i8] }` (tag + data).
|
||||
|
||||
#### Declaration
|
||||
```sx
|
||||
Foo :: enum {
|
||||
variant1;
|
||||
variant2;
|
||||
// Payload-less enum
|
||||
Color :: enum {
|
||||
red;
|
||||
green;
|
||||
blue;
|
||||
}
|
||||
|
||||
// Enum with payloads (tagged union)
|
||||
Shape :: enum {
|
||||
circle: f32; // typed variant
|
||||
rect: s32; // typed variant
|
||||
none; // void variant
|
||||
}
|
||||
```
|
||||
Variants are referenced with dot-prefix syntax: `.variant1`
|
||||
|
||||
#### Construction
|
||||
```sx
|
||||
c := Color.red; // payload-less
|
||||
s :Shape = .circle(3.14); // inferred from context
|
||||
s = .none; // void variant
|
||||
s = Shape.rect(42); // explicit prefix
|
||||
```
|
||||
|
||||
#### Payload Access
|
||||
```sx
|
||||
r := s.circle; // load payload as f32 (undefined behavior if wrong variant active)
|
||||
```
|
||||
|
||||
#### Pattern Matching
|
||||
```sx
|
||||
if s == {
|
||||
case .circle: print("circle\n");
|
||||
case .rect: print("rect\n");
|
||||
case .none: print("none\n");
|
||||
}
|
||||
```
|
||||
|
||||
#### Enum Interpolation
|
||||
Payload-less enums print as `.variant`. Enums with payloads print as `.variant(value)` or `<TypeName tag=N>`:
|
||||
```sx
|
||||
print("{}", s); // .circle(3.140000)
|
||||
```
|
||||
|
||||
### Union Types (Untagged)
|
||||
C-style untagged unions for zero-cost memory overlays (type punning). All fields share the same memory — no tag, no runtime overhead. The LLVM representation is `[max_field_size x i8]`.
|
||||
|
||||
#### Declaration
|
||||
```sx
|
||||
Overlay :: union {
|
||||
f: f32;
|
||||
i: s32;
|
||||
}
|
||||
```
|
||||
All fields must have types (unlike enums, which may have void variants).
|
||||
|
||||
#### Anonymous Struct Fields (Member Promotion)
|
||||
Anonymous `struct` fields inside a union have their members promoted to the union namespace:
|
||||
```sx
|
||||
Vec2 :: union {
|
||||
data: [2]f32;
|
||||
struct { x, y: f32; };
|
||||
}
|
||||
```
|
||||
Access promoted members directly: `v.x`, `v.y` — these are zero-cost GEPs into the same underlying memory as `v.data[0]`, `v.data[1]`.
|
||||
|
||||
#### Initialization
|
||||
Unions must be initialized with `---` (undefined) and then assigned per-field:
|
||||
```sx
|
||||
o :Overlay = ---;
|
||||
o.f = 3.14;
|
||||
print("{}\n", o.i); // reinterpret bits as s32
|
||||
```
|
||||
|
||||
#### Restrictions
|
||||
- Pattern matching (`if x == { case ... }`) is not supported on unions.
|
||||
- Unions cannot be printed directly via `print("{}", union_val)` — access individual fields instead.
|
||||
|
||||
### Struct Types
|
||||
User-defined product types with named fields.
|
||||
```sx
|
||||
@@ -159,45 +234,6 @@ Struct values in string interpolation print as `TypeName{field:value, ...}`:
|
||||
print("{}", v1); // Vec4{x:1.0, y:2.0, z:3.0, w:0.0}
|
||||
```
|
||||
|
||||
### Union Types (Tagged Unions)
|
||||
Sum types where each variant can carry typed data or be void. Internally represented as `{ i64, [max_payload_size x i8] }`.
|
||||
|
||||
#### Declaration
|
||||
```sx
|
||||
Shape :: union {
|
||||
circle: f32; // typed variant
|
||||
rect: s32; // typed variant
|
||||
none; // void variant
|
||||
}
|
||||
```
|
||||
|
||||
#### Construction
|
||||
```sx
|
||||
s :Shape = .circle(3.14); // inferred from context
|
||||
s = .none; // void variant (enum literal syntax)
|
||||
s = Shape.rect(42); // explicit prefix
|
||||
```
|
||||
|
||||
#### Payload Access
|
||||
```sx
|
||||
r := s.circle; // load payload as f32 (undefined behavior if wrong variant active)
|
||||
```
|
||||
|
||||
#### Pattern Matching
|
||||
```sx
|
||||
if s == {
|
||||
case .circle: print("circle\n");
|
||||
case .rect: print("rect\n");
|
||||
case .none: print("none\n");
|
||||
}
|
||||
```
|
||||
|
||||
#### Union Interpolation
|
||||
Union values in string interpolation print as `<TypeName tag=N>`:
|
||||
```sx
|
||||
print("{}", s); // <Shape tag=0>
|
||||
```
|
||||
|
||||
### Array Types
|
||||
Fixed-size arrays with element type and length.
|
||||
```sx
|
||||
@@ -623,7 +659,9 @@ if type == {
|
||||
case enum: result = enum_to_string(cast(type) val);
|
||||
}
|
||||
```
|
||||
Available categories: `int`, `float`, `bool`, `string`, `struct`, `enum`, `union`.
|
||||
Available categories: `int`, `float`, `bool`, `string`, `struct`, `enum`, `vector`, `array`, `slice`, `pointer`, `type`.
|
||||
|
||||
> Note: `case enum:` matches both payload-less enums and tagged enums (enums with payloads). C-style untagged unions are not registered with the Any type system and cannot be matched by category.
|
||||
|
||||
Inside a category arm, `cast(type) val` performs **runtime generic dispatch**: the compiler generates a switch over all types in the category, monomorphizing the callee for each concrete type.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user