mutable decl syntax change

This commit is contained in:
2026-08-05 21:19:41 +02:00
parent 88b94197c9
commit 081a3fd5df
74 changed files with 870 additions and 733 deletions
+2 -1
View File
@@ -8,7 +8,8 @@ roadmap and milestone history.
### source, declarations, and packages
- newline-terminated statements and `#` comments
- immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks
- immutable `name :: value` / `name Type :: value` bindings and mutable `name := value` / `name Type := value` bindings
- `=` is assignment, including `_ = value` sinks; keyed record initializers and named struct field defaults also use `=`
- immutable package globals, mutable runtime globals, function-local mutable locals, and mutable declarations initialized with `undefined`
- package-level functions, globals, native type declarations, and `Name :: alias T`
- directory packages with merged declarations
+1 -1
View File
@@ -222,7 +222,7 @@ Current prototype features:
- Newline-terminated, multiline statements; `}` may terminate a block's final statement
- `#` comments
- Immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks
- Immutable inferred/typed `::` bindings, mutable inferred/typed `:=` locals/globals, and `_` sinks
- Exact-width signed/unsigned integers, `f32`, `f64`, `isize`, `usize`, and loose integer-constrained `int`
- Target-dependent atomic `c_*` primitive types, `c_func`, complete `c_struct`, `opaque`, `anyopaque`, and V1 `ptrcast!(T, ptr)`
- Arrays, sentinel arrays, single-item pointers, many-item pointers, sentinel many-item pointers, slices, sentinel slices, strings, character literals, optionals, and native structs
+19 -20
View File
@@ -12,7 +12,7 @@
- unsigned integers, floats, and target-dependent c scalar types
- atomic `c_*` primitive types remain distinct until target-aware lowering
- `c_func`, complete `c_struct`, and pointer-only `opaque`; `c` remains an ordinary identifier
- keep binding mutability (`::` / `=`) separate from element or pointee mutability (`mut`)
- keep binding mutability (`::` / `:=`) separate from element or pointee mutability (`mut`)
- arrays and indexing
- `[N]T`: array with `N` logical elements
- `[N;S]T`: array with `N` logical elements followed by sentinel `S`
@@ -184,7 +184,7 @@
- undefined values are assigned a poison value (0xaa...)
- allows for something like:
```
a int = undefined
a int := undefined
if (condition) {
a = 42
} else {
@@ -323,7 +323,7 @@
- a `{ ... }` on the right of a declaration or assignment is a *value block*: its final
statement must be `yield <expr>`, which supplies the block's value (the block analogue
of `return`). Supported: `x :: { ...; yield v }` (untyped — the local takes the yield's
natural type), `x T = { ... }` (coerces to `T`), and `target = { ... }` (coerces to the
natural type), `x T := { ... }` (coerces to `T`), and `target = { ... }` (coerces to the
target's type, including complex targets like `a[i] = { ... }`)
- the yielded value is captured *before* the block's defers run (a defer that mutates a
block local can't change what is yielded), reusing the `return` spill-to-temp pattern
@@ -695,9 +695,9 @@
27.8 source-defined mutable runtime globals (implemented)
- allow mutable global declarations in Brolang source for process-global runtime
state, matching the writable-global support already needed for imported C globals
- require source type syntax and an initializer; constraints (`int`/`float`/`range`)
and inferred array counts may resolve through the existing inference fixpoint, but
the final type must be concrete runtime storage
- require an initializer and infer or explicitly declare a concrete runtime storage type;
constraints (`int`/`float`/`range`) and inferred array counts resolve through the existing
inference fixpoint
- emit source-defined mutable globals as writable globals, not constants
- allow `undefined` initializers for runtime storage initialized explicitly by a function
- allow assignment, address-taking, field/index mutation, and pointer passing under
@@ -774,7 +774,7 @@
improving layout or specialization
- the smallest fitting feature is call-local inference of omitted comptime type arguments:
```
values ArrayList(i32) = arraylist.init(mem.c_allocator)
values ArrayList(i32) := arraylist.init(mem.c_allocator)
defer arraylist.deinit(&values)
try arraylist.append(&values, 42)
```
@@ -988,9 +988,9 @@ f: f32 = 3.14
bits := bitcast(f, u32) # IEEE 754 representation
# pointer casts
buf *u8 = get_buffer()
ints *u32 = ptrcast!(u32, buf) # element type change, same pointer shape
writable *mut u8 = constcast!(buf) # explicit unsafe mutability restoration
buf *u8 := get_buffer()
ints *u32 := ptrcast!(u32, buf) # element type change, same pointer shape
writable *mut u8 := constcast!(buf) # explicit unsafe mutability restoration
```
## A word on multi-unwrap
@@ -1069,8 +1069,7 @@ layer:
```bro
UserID :: distinct u32
OuterID :: distinct UserID
index usize = 42
index usize := 42
id UserID :: UserID(index)
raw u32 :: u32(id)
outer OuterID :: OuterID(id)
@@ -1222,7 +1221,7 @@ data :: {
}
# match arms
label []u8 = match p {
label []u8 := match p {
.high: "HIGH", # single expression: implicit yield
.low: {
log("low priority")
@@ -1231,7 +1230,7 @@ label []u8 = match p {
}
# catch handlers (planned; block form deferred in milestone 23 v1)
data []u8 = read(path) catch |e| {
data []u8 := read(path) catch |e| {
log(e)
yield fallback_data # block: explicit yield
}
@@ -1252,7 +1251,7 @@ result :: if a {
}
# yielding to a variable
result int = if a {
result int := if a {
yield 1
} else if b {
yield 2
@@ -1482,7 +1481,7 @@ Fallible functions use ordinary `return` for both channels. If the returned expr
```
parse_section func(p: @mut Parser) void ! ParseError {
start_line Line = p.line
start_line Line := p.line
p.advance()
# ... parsing logic ...
@@ -1497,7 +1496,7 @@ Since errors are just union values, you can also construct them separately:
```
# Construct error value (it's just a union)
e ParseError = .timeout{500}
e ParseError := .timeout{500}
# Return it via error channel later
return e
@@ -1647,7 +1646,7 @@ Brolang provides a libc-backed allocator value:
mem :: import "@std/mem"
process func(input []u8) u64 {
temp ?*mut u8 = mem.alloc(mem.c_allocator, input.len * 2, 1)
temp ?*mut u8 := mem.alloc(mem.c_allocator, input.len * 2, 1)
defer mem.free(mem.c_allocator, temp, input.len * 2, 1)
# ... work with temp ...
@@ -1677,7 +1676,7 @@ mem :: import "@std/mem"
# Allocation escapes via return value — requires allocator
duplicate func(input []u8, allocator mem.Allocator) ?*mut u8 {
result ?*mut u8 = mem.alloc(allocator, input.len, 1)
result ?*mut u8 := mem.alloc(allocator, input.len, 1)
mem.copy(result, input)
return result # caller manages this memory
}
@@ -1690,7 +1689,7 @@ init func(obj @mut MyStruct, allocator mem.Allocator) void {
# No allocation escapes — no allocator needed
process func(input []u8) u64 {
temp ?*mut u8 = mem.alloc(mem.c_allocator, input.len, 1)
temp ?*mut u8 := mem.alloc(mem.c_allocator, input.len, 1)
defer mem.free(mem.c_allocator, temp, input.len, 1)
# ... work with temp ...
return compute_hash(temp)
+5 -17
View File
@@ -5952,7 +5952,7 @@ infer_statements :: proc(
#partial switch statement.kind {
case .Declaration:
if statement.expr == ast.INVALID_EXPR {
// Value block (`x :: { ... yield v }` / `x T = { ... }`): register the
// Value block (`x :: { ... yield v }` / `x T := { ... }`): register the
// binding (its declared type when annotated, else left open) and walk
// the block body. The build pass resolves the yielded value's type
// independently value blocks don't join the demand fixpoint.
@@ -6026,7 +6026,7 @@ infer_statements :: proc(
continue
}
expected_assignment := types.INVALID
if statement.target != ast.INVALID_EXPR {
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
expected_assignment = infer_expr(checker, statement.target, locals^[:], pkg, file, demanded, local_types)
target_expr := checker.ast_module.exprs[statement.target]
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
@@ -6055,7 +6055,7 @@ infer_statements :: proc(
// type onto open-constant operands and poison their family. Operands of an
// arithmetic RHS resolve from their own authoritative uses.
rhs_is_arith := is_arith_kind(checker.ast_module.exprs[statement.expr].kind)
if statement.target != ast.INVALID_EXPR {
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
target_type := expected_assignment
target_expr := checker.ast_module.exprs[statement.target]
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
@@ -10922,7 +10922,7 @@ build_block :: proc(
}
switch statement.kind {
case .Declaration:
// A value block (`x :: { ... yield v }` / `x T = { ... }`): the parser
// A value block (`x :: { ... yield v }` / `x T := { ... }`): the parser
// leaves `expr` invalid and stashes the block in `body`. Build it, then
// declare the local from the yielded value (its type for an untyped `::`).
if statement.expr == ast.INVALID_EXPR {
@@ -11123,7 +11123,7 @@ build_block :: proc(
ctx.problematic^ = ctx.problematic^ || checker.module.exprs[value].kind == .Invalid
}
case .Assignment:
if statement.target != ast.INVALID_EXPR {
if statement.target != ast.INVALID_EXPR && !symbol.is_valid(statement.name) {
target_expr := build_expr(
checker, statement.target, ctx.locals^[:], ctx.global_reads, ctx.calls,
types.INVALID, ctx.pkg, ctx.file,
@@ -14349,18 +14349,6 @@ build_globals :: proc(checker: ^Checker) {
)
expr = invalid_hir_expr(checker, global.span, diagnostic)
}
if !global.immutable {
if !types.is_valid(global.type) {
diagnostic = source.addf(
checker.diagnostics,
global.span,
"mutable global '%s' requires a type annotation",
symbol_text(checker, global.name),
)
global_type = types.I64
expr = invalid_hir_expr(checker, global.span, diagnostic, global_type)
}
}
static_value, is_static := static_integer_value(&checker.module, expr)
is_static = is_static && diagnostic == source.INVALID_DIAGNOSTIC && global.immutable
_ = hir.global_id(len(checker.module.globals))
+10 -3
View File
@@ -133,9 +133,16 @@ lex :: proc(
case ':':
start := cursor
cursor += 1
if cursor < len(bytes) && bytes[cursor] == ':' {
cursor += 1
append_token(&stream, source_file, .Colon_Colon, start, cursor)
if cursor < len(bytes) {
if bytes[cursor] == ':' {
cursor += 1
append_token(&stream, source_file, .Colon_Colon, start, cursor)
} else if bytes[cursor] == '=' {
cursor += 1
append_token(&stream, source_file, .Colon_Equal, start, cursor)
} else {
append_token(&stream, source_file, .Colon, start, cursor)
}
} else {
append_token(&stream, source_file, .Colon, start, cursor)
}
+45 -8
View File
@@ -1868,15 +1868,35 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
had_type = true
}
operator := current(parser)
if operator.kind == .Colon_Colon || operator.kind == .Equal {
if had_type && operator.kind == .Equal {
diagnostic := source.add(
parser.diagnostics,
operator.span,
"mutable declarations use ':=' instead of '='",
)
for current(parser).kind != .Newline &&
current(parser).kind != .Right_Brace &&
current(parser).kind != .Eof {
advance(parser)
}
id := ast.stmt_id(len(parser.module.statements))
append(&parser.module.statements, ast.Stmt{
kind=.Invalid,
span=span_from(name.span, operator.span),
expr=ast.INVALID_EXPR,
diagnostic=diagnostic,
})
return id
}
is_sink := name.kind == .Underscore && operator.kind == .Equal
if operator.kind == .Colon_Colon || operator.kind == .Colon_Equal || is_sink {
advance(parser)
skip_newlines(parser)
kind := ast.Stmt_Kind.Assignment
immutable := false
if operator.kind == .Colon_Colon || had_type {
kind = .Declaration
immutable = operator.kind == .Colon_Colon
kind := ast.Stmt_Kind.Declaration
if is_sink {
kind = .Assignment
}
immutable := operator.kind == .Colon_Colon
// A labeled value block (`x :: blk: { … yield :blk v }`): the label lets a
// `yield :blk` exit the block past a nested `if`. Block-init body + label.
if current(parser).kind == .Identifier && peek(parser).kind == .Colon {
@@ -1954,6 +1974,11 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
}
expr := parse_expression(parser)
assignment_name := symbol.INVALID
target_expr := parser.module.exprs[expr]
if target_expr.kind == .Name && !symbol.is_valid(target_expr.qualifier) {
assignment_name = target_expr.name
}
if _, ok := allow(parser, .Equal); ok {
skip_newlines(parser)
// A labeled value block assigned to a complex target (`a[i] = blk: { … }`).
@@ -1964,6 +1989,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
append(&parser.module.statements, ast.Stmt{
kind=.Assignment,
span=span_from(parser.module.exprs[expr].span, previous(parser).span),
name=assignment_name,
target=expr,
label=label,
expr=ast.INVALID_EXPR,
@@ -1980,6 +2006,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
append(&parser.module.statements, ast.Stmt{
kind=.Assignment,
span=span_from(parser.module.exprs[expr].span, brace.span),
name=assignment_name,
target=expr,
expr=ast.INVALID_EXPR,
body=body,
@@ -1995,6 +2022,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
append(&parser.module.statements, ast.Stmt{
kind=.Assignment,
span=span_from(parser.module.exprs[expr].span, previous(parser).span),
name=assignment_name,
target=expr,
value_control_flow=true,
expr=ast.INVALID_EXPR,
@@ -2008,6 +2036,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
append(&parser.module.statements, ast.Stmt{
kind=.Assignment,
span=span_from(parser.module.exprs[expr].span, parser.module.exprs[value].span),
name=assignment_name,
target=expr,
expr=value,
diagnostic=source.INVALID_DIAGNOSTIC,
@@ -3312,8 +3341,16 @@ parse_top_level :: proc(parser: ^Parser) {
type_syntax = parse_type(parser)
}
operator := current(parser)
if operator.kind != .Colon_Colon && operator.kind != .Equal {
source.add(parser.diagnostics, operator.span, "expected '::' or '=' after top-level name")
if operator.kind == .Equal {
source.add(parser.diagnostics, operator.span, "mutable declarations use ':=' instead of '='")
for current(parser).kind != .Newline && current(parser).kind != .Eof {
advance(parser)
}
_ = finish_statement(parser)
return
}
if operator.kind != .Colon_Colon && operator.kind != .Colon_Equal {
source.add(parser.diagnostics, operator.span, "expected '::' or ':=' after top-level name")
_ = finish_statement(parser)
return
}
+1 -1
View File
@@ -180,7 +180,7 @@ append_runner :: proc(
fmt.sbprintf(&builder, "%s.%s() catch |_| ", alias, symbol.resolve(symbols, test.name))
strings.write_string(&builder, "{\n\t\treturn .expectation_failed\n\t}\n}\n\n")
}
strings.write_string(&builder, "main func() i32 {\n\tfailed i32 = 0\n")
strings.write_string(&builder, "main func() i32 {\n\tfailed i32 := 0\n")
for entry, index in tests {
test_id := entry.function
test := module.functions[test_id]
+1
View File
@@ -16,6 +16,7 @@ Kind :: enum u8 {
Underscore,
Colon,
Colon_Colon,
Colon_Equal,
Equal,
Equal_Equal,
Bang,
+466 -362
View File
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -79,8 +79,8 @@ read_command func() Command {
if rl.IsMouseButtonPressed(rl.MOUSE_BUTTON_LEFT) return .spawn{ rl.GetMousePosition() }
if rl.IsKeyPressed(rl.KEY_SPACE) return .clear
fx f32 = 0.0
fy f32 = 0.0
fx f32 := 0.0
fy f32 := 0.0
if rl.IsKeyDown(rl.KEY_A) fx -= FORCE
if rl.IsKeyDown(rl.KEY_D) fx += FORCE
if rl.IsKeyDown(rl.KEY_W) fy -= FORCE
@@ -130,14 +130,14 @@ step func(b @mut Ball) void {
draw_ball func(b @Ball, highlight bool) void {
col :: color_for(b.kind)
center rl.Vector2 = rl.Vector2{ x = b.x, y = b.y }
center rl.Vector2 := rl.Vector2{ x = b.x, y = b.y }
match b.kind {
.circle: rl.DrawCircleV(center, b.radius, col)
.square: rl.DrawPoly(center, 4, b.radius, 45.0, col)
.triangle: rl.DrawPoly(center, 3, b.radius, 0.0, col)
}
if highlight {
ring rl.Color = rl.Color{ r = 250, g = 245, b = 200, a = 255 }
ring rl.Color := rl.Color{ r = 250, g = 245, b = 200, a = 255 }
rl.DrawPoly(center, 24, b.radius + RING_PAD, 0.0, ring)
}
}
@@ -152,11 +152,11 @@ main func() i32 {
`[click] spawn a shape [WASD/arrows] blow wind
`[space] clear
balls [CAP]mut Ball = undefined
count usize = 0 # number of live balls, in slots 0..count
kc Kind = .circle # next kind to spawn
spin f32 = 1.0 # rotates spawn velocity for variety
at_cap bool = false # show the "at capacity" banner
balls [CAP]mut Ball := undefined
count usize := 0 # number of live balls, in slots 0..count
kc Kind := .circle # next kind to spawn
spin f32 := 1.0 # rotates spawn velocity for variety
at_cap bool := false # show the "at capacity" banner
bg :: rl.Color{ r = 24, g = 26, b = 34, a = 255 }
text :: rl.Color{ r = 225, g = 225, b = 230, a = 255 }
@@ -211,7 +211,7 @@ main func() i32 {
# --- which shape is under the cursor? (optional via a value-loop) ---
mouse :: rl.GetMousePosition()
sel :: for 0..(count) |i| hover: {
c rl.Vector2 = rl.Vector2{ x = balls[i].x, y = balls[i].y }
c rl.Vector2 := rl.Vector2{ x = balls[i].x, y = balls[i].y }
if rl.CheckCollisionPointCircle(mouse, c, balls[i].radius) yield :hover i
yield null
}
@@ -222,7 +222,7 @@ main func() i32 {
for (&balls) |@b, i| {
if (i >= count) break
hot bool = false
hot bool := false
if sel |s| {
if (s == i) hot = true # true only for the hovered ball
}
+2 -2
View File
@@ -19,7 +19,7 @@ native_pair func(value native.Pair) native.Pair {
global_pair native.Pair :: native.Pair { left = 1, right = 2 }
main func() i32 {
pair native.Pair = native_pair(global_pair)
pair native.Pair := native_pair(global_pair)
pair.left = 10
pair = native.echo_pair(pair)
pairs [1]native.Pair :: [pair]
@@ -33,7 +33,7 @@ main func() i32 {
tail = 13,
})
arrays native.Arrays :: native.echo_arrays(native.Arrays { values = [14, 15, 16] })
choice native.Choice = native.Choice { decimal = 1.0 }
choice native.Choice := native.Choice { decimal = 1.0 }
choice.integer = 17
choice = native.echo_choice(choice)
forward native.Forward :: native.echo_forward(native.Forward { value = 19 })
+1 -1
View File
@@ -5,7 +5,7 @@ native :: import "../include/native.h"
# self-referential `?*mut Node` field as C-layout-compatible.
main func() i32 {
node native.Node = native.Node { next = null, value = 7 }
node native.Node := native.Node { next = null, value = 7 }
if node.next |_| {
return 1
}
+3 -3
View File
@@ -1,5 +1,5 @@
hide helper func() i32 {
thing Thing = Thing { value = value }
thing Thing := Thing { value = value }
return thing.value
}
@@ -20,7 +20,7 @@ hide Local_Distinct :: distinct i32
hide Local_Alias :: alias i32
hide value :: 1
hide mutable_value i32 = 1
hide mutable_value i32 := 1
_foreign c_func() i32 {
return 1
@@ -39,6 +39,6 @@ hide Local_C_Record :: c_struct {
}
from_a func() i32 {
record Local_C_Record = Local_C_Record { value = 0 }
record Local_C_Record := Local_C_Record { value = 0 }
return helper() + local_foreign() + i32(record.value)
}
+3 -3
View File
@@ -6,8 +6,8 @@ Box :: struct {
}
from_b func(_input i32) i32 {
_local Box = Box { _value = _input }
record _C_Record = _C_Record { value = 0 }
thing Thing = Thing { value = value }
_local Box := Box { _value = _input }
record _C_Record := _C_Record { value = 0 }
thing Thing := Thing { value = value }
return helper() + thing.value + _local._value + _foreign() + i32(record.value) + dep._visible()
}
@@ -1 +1 @@
bad = 1
bad := undefined
@@ -1,5 +1,5 @@
main func() i32 {
n usize = 4
items [n]mut i32 = undefined
n usize := 4
items [n]mut i32 := undefined
return 0
}
+6 -6
View File
@@ -10,7 +10,7 @@ State :: struct {
diagnostics std.ArrayList(ScanDiagnostic)
}
arrlist_test std.ArrayList(Token) = arraylist.init(mem.c_allocator)
arrlist_test std.ArrayList(Token) := arraylist.init(mem.c_allocator)
init func(allocator mem.Allocator) State {
return State {
@@ -44,11 +44,11 @@ run func() i32 ! mem.AllocError {
state State :: init(mem.c_allocator)
_ = state
values std.ArrayList(i32) = arraylist.init(mem.c_allocator)
values std.ArrayList(i32) := arraylist.init(mem.c_allocator)
defer arraylist.deinit(&values)
if (values.items.len != 0 or values.capacity != 0) return 1
i usize = 0
i usize := 0
while i < 20 : i += 1 {
arraylist.append(&values, i32(i)) catch |_| {
return .out_of_memory
@@ -71,7 +71,7 @@ run func() i32 ! mem.AllocError {
}
if (values.items.len != 1 or values.items[0] != 7 or values.capacity != capacity) return 7
empty_values arraylist.ArrayList([0]u8) = arraylist.init(mem.c_allocator)
empty_values arraylist.ArrayList([0]u8) := arraylist.init(mem.c_allocator)
defer arraylist.deinit(&empty_values)
zero [0]u8 :: []
arraylist.append(&empty_values, zero) catch |_| {
@@ -79,8 +79,8 @@ run func() i32 ! mem.AllocError {
}
if (empty_values.items.len != 1) return 8
failed arraylist.ArrayList(i32) = arraylist.init(i32, fail_allocator)
failed_as_expected bool = false
failed arraylist.ArrayList(i32) := arraylist.init(i32, fail_allocator)
failed_as_expected bool := false
arraylist.append(&failed, 1) catch |_| {
failed_as_expected = true
}
+2 -2
View File
@@ -18,7 +18,7 @@ c_count_shift func(value u8, count c_uint) u8 {
c_count_fold u8 :: c_count_shift(3, 2)
main func() i32 {
buffer Buffer = undefined
buffer Buffer := undefined
if (folded != 0) return 1
if (contextual != 255) return 28
if (contextual_shift != 128) return 29
@@ -50,7 +50,7 @@ main func() i32 {
if ((c_ushort(240) xor c_ushort(255)) != 15) return 26
if ((c_longlong(64) <<| 60) != maxval!(c_longlong)) return 27
value u8 = 3
value u8 := 3
value <<= 2
value |= 1
value xor= 5
+6 -6
View File
@@ -7,8 +7,8 @@
main func() i32 {
# 1. `break` out of a `while` once i reaches 5.
i i32 = 0
a i32 = 0
i i32 := 0
a i32 := 0
while i < 100 : i += 1 {
if (i == 5) break
a += 1
@@ -16,7 +16,7 @@ main func() i32 {
if (a != 5) return 101
# 2. `continue` past n == 3 while summing 0..9 (45 - 3 = 42).
b i32 = 0
b i32 := 0
for 0..10 |n| {
if (n == 3) continue
b = b + n
@@ -25,7 +25,7 @@ main func() i32 {
# 3. Nested loops: the inner `break` exits only the inner loop, so the outer
# loop still runs all three iterations (each contributing one y == 0 pass).
c i32 = 0
c i32 := 0
for 0..3 |x| {
for 0..3 |y| {
if (y == 1) break
@@ -38,7 +38,7 @@ main func() i32 {
# 4. `continue` on the final element of an inclusive range bounded by the
# element type's maximum must exit cleanly, not overflow the increment.
hi u8 :: 255
d i32 = 0
d i32 := 0
for 0..=hi |v| {
if (v == 255) continue
d += 1
@@ -47,7 +47,7 @@ main func() i32 {
# 5. `while true` is exitable via `break` (so it is not an infinite loop and
# the code after it is reachable).
e i32 = 0
e i32 := 0
while true {
e += 1
if (e == 7) break
@@ -1,7 +1,7 @@
# Compound assignment (`+=`, `-=`, `*=`, `/=`) and explicit integer division.
check_float func() i32 {
x f64 = 10.0
x f64 := 10.0
x /= 4.0 # 2.5
x *= 2.0 # 5.0
x -= 1.0 # 4.0
@@ -13,7 +13,7 @@ check_float func() i32 {
}
check_unsigned func() i32 {
n u32 = 100
n u32 := 100
n = divtrunc!(n, 7) # 14
n -= 4 # 10
if n == 10 {
@@ -23,7 +23,7 @@ check_unsigned func() i32 {
}
main func() i32 {
total i32 = 0
total i32 := 0
total += 10 # 10
total -= 3 # 7
total *= 4 # 28
@@ -33,7 +33,7 @@ main func() i32 {
total = total + 2 * 3 - 4
# compound assignment as a while-loop update
i i32 = 0
i i32 := 0
while i < 5 : i += 1 {
total += 1 # +5 => 21
}
+1 -1
View File
@@ -15,7 +15,7 @@ nested func(value int) int {
}
make_array func($N usize) [N]u8 {
data [N]u8 = undefined
data [N]u8 := undefined
return data
}
@@ -14,13 +14,13 @@ id func($T type, value T) T {
}
buffer func($T type, $N usize, value T) [N]T {
data [N]T = undefined
data [N]T := undefined
_ = value
return data
}
zero func($T type) T {
value T = undefined
value T := undefined
return value
}
@@ -86,12 +86,12 @@ main func() i32 {
if fixed_len(&fixed) != 3 {
return 7
}
assigned i32 = 1
assigned i32 := 1
assigned = zero()
_ = assigned
_ = take_i32(zero())
_ = return_zero()
optional ?u32 = null
optional ?u32 := null
if !same_type(?u32, optional) {
return 8
}
+11 -11
View File
@@ -32,8 +32,8 @@ make_point func() Point {
}
sum_loop func(limit i32) i32 {
total i32 = 0
i i32 = 0
total i32 := 0
i i32 := 0
while i < limit {
i += 1
if i == 2 {
@@ -45,8 +45,8 @@ sum_loop func(limit i32) i32 {
}
sum_for func() i32 {
total i32 = 0
values [_]i32 = [1, 2, 3]
total i32 := 0
values [_]i32 := [1, 2, 3]
for values |value, index| {
total += value + index
}
@@ -54,7 +54,7 @@ sum_for func() i32 {
}
defer_value func() i32 {
value i32 = 1
value i32 := 1
{
defer value += 10
value += 1
@@ -140,7 +140,7 @@ use_try func() i32 ! Error {
}
ct_errdefer func(fail bool) i32 ! Error {
trace i32 = 0
trace i32 := 0
defer trace = trace * 10 + 1
errdefer |err| {
if (err == .bad) trace = trace * 10 + 2
@@ -151,7 +151,7 @@ ct_errdefer func(fail bool) i32 ! Error {
}
ct_try_errdefer func() i32 ! Error {
trace i32 = 0
trace i32 := 0
defer trace = trace * 10 + 4
errdefer |err| {
if (err == .bad) trace = trace * 10 + 5
@@ -185,20 +185,20 @@ alias_add func(left @mut i32, right @mut i32) void {
}
storage_mutation func() i32 {
values [3]mut i32 = [1, 2, 3]
values [3]mut i32 := [1, 2, 3]
values[0] += 1
bump_ptr(&values[1])
view []mut i32 = values[..]
view []mut i32 := values[..]
for view |@item| {
item^ += 1
}
pointer *mut i32 = view.ptr
pointer *mut i32 := view.ptr
pointer[2] += 1
alias_add(&values[0], &view[0])
box Box = Box { point = Point { x = 2, y = 3 } }
box Box := Box { point = Point { x = 2, y = 3 } }
match box {
.point |@p|: p.x += values[1]
.empty: values[0] = values[0]
@@ -1,5 +1,5 @@
make_array func($N usize) [N]u8 {
data [N]u8 = undefined
data [N]u8 := undefined
return data
}
@@ -6,10 +6,10 @@ observe func(counter @mut i32, value ?i32) ?i32 {
}
main func() i32 {
total i32 = 0
total i32 := 0
# present optional scalar -> binds v to the unwrapped value
a ?i32 = 40
a ?i32 := 40
if a |v| {
total = total + v # 40
} else {
@@ -17,7 +17,7 @@ main func() i32 {
}
# null -> else branch taken; the binding is not in scope there
b ?i32 = null
b ?i32 := null
if b |v| {
total = total + v
} else {
@@ -25,20 +25,20 @@ main func() i32 {
}
# optional pointer present -> binds q to a non-null @i32; deref proves it
n i32 = 0
p ?@i32 = &n
n i32 := 0
p ?@i32 := &n
if p |q| {
total = total + q^ # +0
}
# optional pointer null -> skipped
z ?@i32 = null
z ?@i32 := null
if z |_| {
total = total + 1000
}
# guarded multi-unwrap exposes every capture to the guard and then-block
age ?i32 = 2
age ?i32 := 2
if a and age |value, years : value + years == 42| {
total = total
} else {
@@ -46,7 +46,7 @@ main func() i32 {
}
# parenthesized chains and three-value unwraps are equivalent
bonus ?i32 = 0
bonus ?i32 := 0
if (a and age and bonus) |value, years, extra : value + years + extra == 42| {
total = total
} else {
@@ -64,7 +64,7 @@ main func() i32 {
}
# a failed unwrap prevents later expressions from being evaluated
calls i32 = 0
calls i32 := 0
if b and observe(&calls, age) |missing, observed| {
total = total + missing + observed
}
+3 -3
View File
@@ -23,7 +23,7 @@ noisy func() bool {
}
main func() i32 {
total i32 = 0
total i32 := 0
# comparisons drive if / else if / else
total = total + classify(-5) # 1
@@ -45,9 +45,9 @@ main func() i32 {
}
# block scoping: inner bindings do not escape the block
x i32 = 1
x i32 := 1
if x == 1 {
inner_x i32 = 100
inner_x i32 := 100
if inner_x == 100 {
total = total + 5 # 40
}
+9 -9
View File
@@ -7,7 +7,7 @@
# The return value is captured before defers run, so the mutation here does not
# change what is returned (Zig semantics).
spill_check func() i32 {
x i32 = 5
x i32 := 5
defer x = 999
return x
}
@@ -15,7 +15,7 @@ spill_check func() i32 {
# A function-scope defer runs only at function exit; a `break` runs the loop-body
# defer but NOT the enclosing function-scope defer.
enclosing_defer_check func() i32 {
v i32 = 0
v i32 := 0
defer v = v + 100
for 0..3 |i| {
defer v = v + 1
@@ -89,7 +89,7 @@ main func() i32 {
if (spill_check() != 5) return 101
# 2. LIFO ordering, run at end of each loop iteration.
r i32 = 0
r i32 := 0
for 0..1 |i| {
defer r = r * 2 + 1 # registered first -> runs last
defer r = r * 2 # registered second -> runs first
@@ -99,16 +99,16 @@ main func() i32 {
# 3. scoped bare block + scoped defer (defer fires at the closing brace, and
# the block-local is not visible afterwards).
a i32 = 1
a i32 := 1
{
defer a = 4
c i32 = 3
c i32 := 3
_ = c
}
if (a != 4) return 103
# 4. `defer { ... }` block: all its statements run (in order) at scope close.
s i32 = 0
s i32 := 0
{
defer {
s = s + 1
@@ -119,7 +119,7 @@ main func() i32 {
if (s != 60) return 104 # 5 -> 6 -> 60
# 5. `break` flushes the loop-body defer.
bc i32 = 0
bc i32 := 0
for 0..5 |i| {
defer bc = bc + 1
if (i == 2) break
@@ -127,7 +127,7 @@ main func() i32 {
if (bc != 3) return 105 # i=0,1 fall-through + i=2 break
# 6. `continue` flushes the loop-body defer.
cc i32 = 0
cc i32 := 0
for 0..3 |i| {
defer cc = cc + 1
if (i == 1) continue
@@ -139,7 +139,7 @@ main func() i32 {
if (enclosing_defer_check() != 2) return 107
# 8. errdefer is skipped on success; ordinary defers stay interleaved.
trace i32 = 0
trace i32 := 0
if ((explicit_cleanup(false, &trace) catch 0) != 7 or trace != 31) return 108
# 9. Explicit errors run errdefer and expose the captured error.
+12 -12
View File
@@ -24,9 +24,9 @@ take func(value LocalID) LocalID {
main func() i32 {
id LocalID :: LocalID(7)
copy LocalID = take(id)
maybe ?LocalID = copy
pointer @LocalID = &copy
copy LocalID := take(id)
maybe ?LocalID := copy
pointer @LocalID := &copy
point PointID :: PointID(Point { x = 1, y = 2 })
bytes Bytes :: Bytes([3, 4])
wrapped WrappedID :: WrappedID(id)
@@ -64,15 +64,15 @@ main func() i32 {
return 8
}
arithmetic Signed = Signed(4)
arithmetic Signed := Signed(4)
arithmetic += 3
arithmetic -= 2
arithmetic *= 5
fraction Real = Real(3.0)
fraction Real := Real(3.0)
fraction /= 2.0
if arithmetic != 25 or fraction != 1.5 { return 9 }
bits Mask = Mask(3)
bits Mask := Mask(3)
bits |= 8
bits xor= 2
bits &= 9
@@ -81,18 +81,18 @@ main func() i32 {
bits <<|= u8(5)
if bits != 255 { return 10 }
values [10]u8 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
values [10]u8 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if values[LocalID(4)] != 4 { return 11 }
section []u8 = values[LocalID(2)..LocalID(5)]
section []u8 := values[LocalID(2)..LocalID(5)]
if section.len != 3 or section[usize(0)] != 2 or section[usize(2)] != 4 { return 12 }
if u32(id) != 7 or usize(id) != 7 or f64(id) != 7.0 { return 13 }
extracted LocalID = LocalID(wrapped)
extracted LocalID := LocalID(wrapped)
if extracted != id { return 14 }
minimum Signed = minval!(Signed)
maximum Mask = maxval!(Mask)
nested_max WrappedID = maxval!(WrappedID)
minimum Signed := minval!(Signed)
maximum Mask := maxval!(Mask)
nested_max WrappedID := maxval!(WrappedID)
if i32(minimum) != minval!(i32) or u8(maximum) != 255 or u32(nested_max) != maxval!(u32) {
return 15
}
+1 -1
View File
@@ -17,7 +17,7 @@ identity c_func(value State) State {
}
main func() i32 {
state State = identity(.running)
state State := identity(.running)
values [2]State :: [.started, State.stopped]
animal animals.Animal :: animals.Animal.dog
if same(state, .running) and
+4 -4
View File
@@ -125,7 +125,7 @@ inline_detail func(value i32) i32 ! union(enum) {
}
main func() i32 {
acc i32 = 0
acc i32 := 0
a :: maybe(0) catch 7
b :: maybe(4) catch 99
@@ -166,11 +166,11 @@ main func() i32 {
acc = acc + a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p
acc = acc + pick(.left)
r Right = .right
r Right := .right
acc = acc + pick(r)
box BoxA = .a{8}
box BoxA := .a{8}
acc = acc + payload(box)
empty BoxB = .b
empty BoxB := .b
acc = acc + payload(empty)
acc = acc + payload(.a{9})
+3 -3
View File
@@ -5,9 +5,9 @@ pass func(value range) range {
}
main func() i32 {
total i32 = 0
total i32 := 0
items [3]mut i32 = [1, 2, 3]
items [3]mut i32 := [1, 2, 3]
for items |item, index| {
total = total + item
_ = index
@@ -17,7 +17,7 @@ main func() i32 {
item^ = item^ + 1
}
view []mut i32 = items[..]
view []mut i32 := items[..]
for view |@item, index| {
item^ = item^ + 1
_ = index
+10 -10
View File
@@ -6,23 +6,23 @@ make_range func(calls @mut i32, end usize) range {
global_range :: 0..1
main func() i32 {
total i32 = 0
total i32 := 0
first u8 = 254
last u8 = 255
first u8 := 254
last u8 := 255
for first..=last |value| {
_ = value
total = total + 1
}
signed_start i8 = -2
signed_end i8 = 1
signed_start i8 := -2
signed_end i8 := 1
for signed_start..signed_end |value| {
_ = value
total = total + 1
}
limit usize = 3
limit usize := 3
for 0..(limit + 1) |value| {
_ = value
total = total + 1
@@ -41,19 +41,19 @@ main func() i32 {
total = total + 100
}
empty [0]i32 = []
empty [0]i32 := []
for empty |value| {
_ = value
total = total + 100
}
pointed i32 = 3
pointers [1]@mut i32 = [&pointed]
pointed i32 := 3
pointers [1]@mut i32 := [&pointed]
for pointers |pointer| {
total = total + pointer^
}
calls i32 = 0
calls i32 := 0
for make_range(&calls, 2) |value| {
_ = value
total = total + 1
@@ -1,6 +1,6 @@
main func() i32 {
items [3]mut i32 = undefined
i int = 1
items [3]mut i32 := undefined
i int := 1
items[i] = 42
return 0
}
@@ -1,6 +1,6 @@
main func() i32 {
items [3]mut i32 = undefined
i i32 = 1
items [3]mut i32 := undefined
i i32 := 1
items[i] = 42
return 0
}
+5 -5
View File
@@ -68,8 +68,8 @@ main func() i32 {
return 2
}
a Value = .number{41}
b Value = .number{41}
a Value := .number{41}
b Value := .number{41}
if !equal_value(a, b) or equal_value(a, .pair{left = 41, right = 0}) {
return 3
}
@@ -78,8 +78,8 @@ main func() i32 {
return 4
}
pair_a Value = .pair{left = 2, right = 3}
pair_b Value = .pair{left = 2, right = 3}
pair_a Value := .pair{left = 2, right = 3}
pair_b Value := .pair{left = 2, right = 3}
if !equal_value(pair_a, pair_b) or !equal_value(.empty, .empty) {
return 5
}
@@ -88,7 +88,7 @@ main func() i32 {
return 6
}
empty Value = .empty
empty Value := .empty
increment(&empty)
return 0
}
@@ -1,4 +1,4 @@
bad int = 4
bad int := 4
read_bad func() int {
return bad
+2 -2
View File
@@ -85,7 +85,7 @@ bad_writer func() io.Writer {
}
rejects_bad_read func() bool {
buffer [1]mut u8 = [0]
buffer [1]mut u8 := [0]
_ = io.read(bad_reader(), buffer[..]) catch |err| {
return err == .read_failed
}
@@ -108,7 +108,7 @@ rejects_bad_write func() bool {
main func(init process.Init) i32 {
system io.Io :: init.io
buffer [2]mut u8 = [0, 0]
buffer [2]mut u8 := [0, 0]
count usize :: io.read(ok_reader(), buffer[..]) catch 0
if count != 2 or buffer[0] != 'o' or buffer[1] != 'k' {
return 1
+9 -9
View File
@@ -63,18 +63,18 @@ make_box func() Box {
}
main func() i32 {
acc i32 = 0
acc i32 := 0
dog Data = Data{ dog = 9 }
bird Data = Data{ bird = 38 }
dog Data := Data{ dog = 9 }
bird Data := Data{ bird = 38 }
acc = acc + describe(dog) + describe(bird) # 10 + 40 = 50
# same-type multi-pattern capture
acc = acc + payload_of(dog) + payload_of(bird) # 9 + 38 = 47
# enum statement match, exhaustive, with a multi-pattern arm
a Animal = .bird
rank i32 = 0
a Animal := .bird
rank i32 := 0
match a {
.dog, .cat: rank = 1
.bird: rank = 3
@@ -89,7 +89,7 @@ main func() i32 {
acc = acc + legs # +2
# scalar match: a range arm, a multi-literal arm, and a mandatory else
bucket i32 = 0
bucket i32 := 0
match rank {
0..3: bucket = 1 # exclusive 0,1,2 — does not include 3
3, 4: bucket = 5 # rank is 3
@@ -98,8 +98,8 @@ main func() i32 {
acc = acc + bucket # +5
# void-payload variant: contextual construction (`.empty` coerces to Box) + no-capture arm
e Box = .empty
hit i32 = 0
e Box := .empty
hit i32 := 0
match e {
.point |pt|: hit = pt.x
.empty: hit = 7
@@ -107,7 +107,7 @@ main func() i32 {
acc = acc + hit # +7
# pointer capture mutates the subject's payload in place
b Box = Box{ point = Point{ x = 1, y = 2 } }
b Box := Box{ point = Point{ x = 1, y = 2 } }
match b {
.point |@p|: p.x = 10
.empty: hit = hit
@@ -1,7 +1,7 @@
mem :: import "@std/mem"
raw_allocator_test func() i32 {
resized ?*mut u8 = mem.raw_realloc(mem.c_allocator, null, 0, 4, 1)
resized ?*mut u8 := mem.raw_realloc(mem.c_allocator, null, 0, 4, 1)
if resized |bytes| {
bytes[0] = 10
bytes[1] = 20
@@ -11,7 +11,7 @@ raw_allocator_test func() i32 {
return 20
}
grown ?*mut u8 = mem.raw_realloc(mem.c_allocator, resized, 4, 8, 1)
grown ?*mut u8 := mem.raw_realloc(mem.c_allocator, resized, 4, 8, 1)
if grown |bytes| {
resized = grown
if bytes[0] != 10 or bytes[1] != 20 or bytes[2] != 30 or bytes[3] != 40 {
@@ -23,7 +23,7 @@ raw_allocator_test func() i32 {
return 22
}
shrunk ?*mut u8 = mem.raw_realloc(mem.c_allocator, resized, 8, 2, 1)
shrunk ?*mut u8 := mem.raw_realloc(mem.c_allocator, resized, 8, 2, 1)
if shrunk |bytes| {
resized = shrunk
if bytes[0] != 10 or bytes[1] != 20 {
@@ -35,7 +35,7 @@ raw_allocator_test func() i32 {
return 24
}
invalid ?*mut u8 = mem.raw_realloc(mem.c_allocator, resized, 2, 4, 24)
invalid ?*mut u8 := mem.raw_realloc(mem.c_allocator, resized, 2, 4, 24)
if invalid |memory| {
mem.raw_free(mem.c_allocator, memory, 4, 24)
mem.raw_free(mem.c_allocator, resized, 2, 1)
@@ -54,14 +54,14 @@ raw_allocator_test func() i32 {
return 27
}
over_aligned ?*mut u8 = mem.raw_alloc(mem.c_allocator, 4, 32)
over_aligned ?*mut u8 := mem.raw_alloc(mem.c_allocator, 4, 32)
if over_aligned |bytes| {
bytes[0] = 11
bytes[1] = 22
} else {
return 28
}
over_aligned_grown ?*mut u8 = mem.raw_realloc(mem.c_allocator, over_aligned, 4, 8, 32)
over_aligned_grown ?*mut u8 := mem.raw_realloc(mem.c_allocator, over_aligned, 4, 8, 32)
if over_aligned_grown |bytes| {
if bytes[0] != 11 or bytes[1] != 22 {
mem.raw_free(mem.c_allocator, over_aligned_grown, 8, 32)
@@ -73,19 +73,19 @@ raw_allocator_test func() i32 {
return 30
}
zero_alignment ?*mut u8 = mem.raw_alloc(mem.c_allocator, 8, 0)
zero_alignment ?*mut u8 := mem.raw_alloc(mem.c_allocator, 8, 0)
if zero_alignment |memory| {
mem.raw_free(mem.c_allocator, memory, 8, 0)
return 1
}
bad_alignment ?*mut u8 = mem.raw_alloc(mem.c_allocator, 8, 24)
bad_alignment ?*mut u8 := mem.raw_alloc(mem.c_allocator, 8, 24)
if bad_alignment |memory| {
mem.raw_free(mem.c_allocator, memory, 8, 24)
return 2
}
aligned ?*mut u8 = mem.raw_alloc(mem.c_allocator, 64, 32)
aligned ?*mut u8 := mem.raw_alloc(mem.c_allocator, 64, 32)
defer mem.raw_free(mem.c_allocator, aligned, 64, 32)
if aligned |bytes| {
bytes[0] = 1
+16 -16
View File
@@ -21,9 +21,9 @@ task_list_init func(allocator mem.Allocator) TaskList {
}
alloc_i32s func(allocator mem.Allocator, count usize) ?[]mut i32 {
fallback [1]mut i32 = undefined
failed bool = false
values []mut i32 = mem.alloc(allocator, count) catch |_| {
fallback [1]mut i32 := undefined
failed bool := false
values []mut i32 := mem.alloc(allocator, count) catch |_| {
failed = true
yield (&fallback).ptr[..0]
}
@@ -42,14 +42,14 @@ task_list_reserve func(list @mut TaskList, capacity usize) bool {
return true
}
new_ids ?[]mut i32 = alloc_i32s(list.allocator, capacity)
new_priorities ?[]mut i32 = alloc_i32s(list.allocator, capacity)
new_durations ?[]mut i32 = alloc_i32s(list.allocator, capacity)
new_ids ?[]mut i32 := alloc_i32s(list.allocator, capacity)
new_priorities ?[]mut i32 := alloc_i32s(list.allocator, capacity)
new_durations ?[]mut i32 := alloc_i32s(list.allocator, capacity)
if (new_ids and new_priorities and new_durations) |ids, priorities, durations| {
if list.len > 0 {
if (list.ids and list.priorities and list.durations) |old_ids, old_priorities, old_durations| {
i usize = 0
i usize := 0
while i < list.len : i += 1 {
ids[i] = old_ids[i]
priorities[i] = old_priorities[i]
@@ -82,7 +82,7 @@ task_list_reserve func(list @mut TaskList, capacity usize) bool {
task_list_push func(list @mut TaskList, id i32, priority i32, duration i32) bool {
if list.len == list.capacity {
new_capacity usize = 2
new_capacity usize := 2
if list.capacity != 0 {
new_capacity = list.capacity * 2
}
@@ -92,7 +92,7 @@ task_list_push func(list @mut TaskList, id i32, priority i32, duration i32) bool
}
if (list.ids and list.priorities and list.durations) |ids, priorities, durations| {
index usize = list.len
index usize := list.len
ids[index] = id
priorities[index] = priority
durations[index] = duration
@@ -113,11 +113,11 @@ task_list_best_id func(list @mut TaskList) i32 {
}
if (list.ids and list.priorities and list.durations) |ids, priorities, durations| {
best_index usize = 0
best_score i32 = task_score(priorities[0], durations[0])
i usize = 1
best_index usize := 0
best_score i32 := task_score(priorities[0], durations[0])
i usize := 1
while i < list.len : i += 1 {
score i32 = task_score(priorities[i], durations[i])
score i32 := task_score(priorities[i], durations[i])
if score > best_score {
best_score = score
best_index = i
@@ -130,9 +130,9 @@ task_list_best_id func(list @mut TaskList) i32 {
}
task_list_total_duration func(list @mut TaskList) i32 {
total i32 = 0
total i32 := 0
if list.durations |durations| {
i usize = 0
i usize := 0
while i < list.len : i += 1 {
total += durations[i]
}
@@ -152,7 +152,7 @@ task_list_deinit func(list @mut TaskList) void {
}
task_list_test func() i32 {
tasks TaskList = task_list_init(mem.c_allocator)
tasks TaskList := task_list_init(mem.c_allocator)
defer task_list_deinit(&tasks)
if task_list_push(&tasks, 101, 3, 5) == false {
+14 -14
View File
@@ -30,8 +30,8 @@ hide probe_vtable mem.AllocatorVTable :: mem.AllocatorVTable {
typed_allocator_test func() i32 {
if (sizeof!(mem.Allocator) != 16) return 31
first_calls [1]mut usize = [0]
second_calls [1]mut usize = [0]
first_calls [1]mut usize := [0]
second_calls [1]mut usize := [0]
first_allocator mem.Allocator :: mem.Allocator {
context = &first_calls,
vtable = &probe_vtable,
@@ -47,9 +47,9 @@ typed_allocator_test func() i32 {
_ = mem.raw_alloc(second_allocator, 1, 1)
if (first_calls[0] != 3 or second_calls[0] != 1) return 32
i32_fallback [1]mut i32 = undefined
empty_failed bool = false
empty []mut i32 = mem.alloc(first_allocator, 0) catch |_| {
i32_fallback [1]mut i32 := undefined
empty_failed bool := false
empty []mut i32 := mem.alloc(first_allocator, 0) catch |_| {
empty_failed = true
yield (&i32_fallback).ptr[..0]
}
@@ -57,9 +57,9 @@ typed_allocator_test func() i32 {
mem.free(first_allocator, empty)
if (first_calls[0] != 3) return 33
zero_sized_fallback [1]mut [0]u8 = undefined
zero_sized_failed bool = false
zero_sized []mut [0]u8 = mem.alloc([0]u8, first_allocator, 3) catch |_| {
zero_sized_fallback [1]mut [0]u8 := undefined
zero_sized_failed bool := false
zero_sized []mut [0]u8 := mem.alloc([0]u8, first_allocator, 3) catch |_| {
zero_sized_failed = true
yield (&zero_sized_fallback).ptr[..0]
}
@@ -68,22 +68,22 @@ typed_allocator_test func() i32 {
mem.free([0]u8, first_allocator, zero_sized)
if (first_calls[0] != 3) return 35
u64_fallback [1]mut u64 = undefined
overflow_fallback_failed bool = false
overflow_fallback []mut u64 = mem.alloc(first_allocator, 0) catch |_| {
u64_fallback [1]mut u64 := undefined
overflow_fallback_failed bool := false
overflow_fallback []mut u64 := mem.alloc(first_allocator, 0) catch |_| {
overflow_fallback_failed = true
yield (&u64_fallback).ptr[..0]
}
if (overflow_fallback_failed) return 37
overflow_failed bool = false
overflow_failed bool := false
_ = mem.alloc(u64, first_allocator, maxval!(usize)) catch |_| {
overflow_failed = true
yield overflow_fallback
}
if (overflow_failed == false or first_calls[0] != 3) return 40
typed_failed bool = false
typed []mut i32 = mem.alloc(mem.c_allocator, 4) catch |_| {
typed_failed bool := false
typed []mut i32 := mem.alloc(mem.c_allocator, 4) catch |_| {
typed_failed = true
yield (&i32_fallback).ptr[..0]
}
+6 -6
View File
@@ -48,26 +48,26 @@ score_for func(k Kind) i32 {
}
main func() i32 {
items [LEN]mut i32 = undefined
items [LEN]mut i32 := undefined
items[0] = 10
items[1] = 20
idx u8 = 2
idx u8 := 2
items[idx] = items[0] + items[1]
if (items[2] != 30) return 1
native_i i32 = 12
native_i i32 := 12
if (take_c_int(native_i) != 12) return 2
native_u u8 = 7
native_u u8 := 7
if (take_c_uchar(native_u) != 7) return 3
native_f f32 = 3.25
native_f f32 := 3.25
cf :: take_c_float(native_f)
if (cf < 3.0 or cf > 4.0) return 4
if (cf == 0.0) return 5
native_d f64 = 5.0
native_d f64 := 5.0
cd :: take_c_double(native_d)
if (cd != 5.0) return 6
+2 -2
View File
@@ -86,8 +86,8 @@ main func(init process.Init) i32 {
}
writer io.Writer :: io.stdout(init.io)
positive f64 = 1.0
zero f64 = 0.0
positive f64 := 1.0
zero f64 := 0.0
infinity f64 :: positive / zero
nan f64 :: zero / zero
io.print(writer, "{} {} {} {} {s} {d} {b} {o} {x} {X} {c} {e} {{}} {d} {b} {} {} {e}\n", {
+6 -6
View File
@@ -2,11 +2,11 @@ Point :: struct {
x i32
}
counter int = 0
ratio float = 1
span range = 0..2
point Point = Point { x = 1 }
values [_]mut i32 = [10, 20]
counter := i32(0)
ratio := 1.0
span := 0..2
point Point := Point { x = 1 }
values [_]mut i32 := [10, 20]
bump func(value @mut i32) void {
value^ += 1
@@ -19,7 +19,7 @@ main func() i32 {
point.x += counter
values[1] = point.x
total i32 = counter + point.x + values[1]
total i32 := counter + point.x + values[1]
for span |i| {
total += i
}
+1 -1
View File
@@ -1,5 +1,5 @@
main func() i32 {
value i32 = 1
value := i32(1)
value = value + 2
return value
}
+1 -1
View File
@@ -1,4 +1,4 @@
main func() void {
value i8 = 127
value i8 := 127
_ = value + 1
}
+1 -1
View File
@@ -11,7 +11,7 @@ sum_brolang func(a, b int) int {
}
main func() void {
y int = 4
y int := 4
a_add_b_c :: sum_c(1, 2)
a_add_b_brolang :: sum_brolang(1, 2)
_ = y
+1 -1
View File
@@ -1,5 +1,5 @@
main func() i32 {
flag bool = true
flag bool := true
value :: i32(flag)
return value
}
+2 -2
View File
@@ -16,7 +16,7 @@ Thing :: union(enum) {
}
main func() i32 {
x Data = Data{ bird = 37 }
y Thing = Thing{ a = 5 }
x Data := Data{ bird = 37 }
y Thing := Thing{ a = 5 }
return x.bird + y.a
}
+4 -4
View File
@@ -9,7 +9,7 @@ format func() []u8 {
}
sum func($T type, value T) i32 {
total i32 = 0
total i32 := 0
match typeinfo!(T) {
.record |record|: inline for record.fields |field| {
total += i32(field!(value, field.name))
@@ -20,7 +20,7 @@ sum func($T type, value T) i32 {
}
static_control func($T type, value T) i32 {
total i32 = 0
total i32 := 0
match typeinfo!(T) {
.record |record|: inline for record.fields |field| {
{
@@ -49,7 +49,7 @@ row_value func(row Row) i32 {
}
static_aggregates func() i32 {
total i32 = 0
total i32 := 0
inline for {Row {value = 2}, Row {value = 40}} |row| {
total += row_value(row)
}
@@ -57,7 +57,7 @@ static_aggregates func() i32 {
}
main func() i32 {
numbers Numbers = Numbers {1, 2, 39}
numbers Numbers := Numbers {1, 2, 39}
singleton :: {42,}
empty :: {}
block_value :: {
+1 -1
View File
@@ -4,6 +4,6 @@ Val :: union {
}
main func() i32 {
x Val = Val{ n = 42 }
x Val := Val{ n = 42 }
return x.n
}
+3 -3
View File
@@ -1,8 +1,8 @@
warn_only func(value i32, unused i32) i32 {
local i32 = 1
write_only i32 = 2
local i32 := 1
write_only i32 := 2
write_only = 3
consumed i32 = value
consumed i32 := value
_ = consumed
return value
}
+8 -8
View File
@@ -1,31 +1,31 @@
# Milestone 5: boolean while loops with optional post-iteration updates.
return_before_update func() i32 {
i i32 = 0
i i32 := 0
while true : i = i + 1 {
return i
}
}
main func() i32 {
total i32 = 0
total i32 := 0
# ordinary condition and update
i u32 = 0
i u32 := 0
while i < 5 : i = i + 1 {
total = total + 2
}
# equivalent parenthesized header
j u32 = 0
j u32 := 0
while (j < 4) : (j = j + 1) {
total = total + 3
}
# nested loops and body-local storage
outer u32 = 0
outer u32 := 0
while outer < 2 : outer = outer + 1 {
inner u32 = 0
inner u32 := 0
while inner < 3 : inner = inner + 1 {
total = total + 2
}
@@ -33,9 +33,9 @@ main func() i32 {
# Body-local storage stays scoped to the body. The update still targets
# the mutable k declared before the loop.
k u32 = 0
k u32 := 0
while k < 4 : k = k + 1 {
body_k u32 = 100
body_k u32 := 100
if body_k == 100 {
total = total + 2
}
+12 -12
View File
@@ -19,7 +19,7 @@ basic func() i32 {
# Typed `T =`: the yield coerces to the annotation.
typed func() i64 {
x i64 = {
x i64 := {
yield 100
}
return x
@@ -29,7 +29,7 @@ typed func() i64 {
# local, but the captured value is unchanged.
spill func() i32 {
v :: {
n i32 = 5
n i32 := 5
defer n = 999
yield n
}
@@ -38,7 +38,7 @@ spill func() i32 {
# Reassignment into an existing mutable local.
reassign func() i32 {
r i32 = 0
r i32 := 0
r = {
yield 7
}
@@ -61,13 +61,13 @@ vif_untyped func(sel i32) i32 {
# Typed `T =`: every branch coerces to the annotation.
vif_typed func(sel i32) i32 {
r i32 = if (sel == 0) { yield 100 } else { yield 200 }
r i32 := if (sel == 0) { yield 100 } else { yield 200 }
return r
}
# Assigned into an existing local.
vif_reassign func(sel i32) i32 {
r i32 = 0
r i32 := 0
r = if (sel == 0) { yield 7 } else { yield 9 }
return r
}
@@ -76,7 +76,7 @@ vif_reassign func(sel i32) i32 {
# the yield.
vif_defer func() i32 {
r :: if (true) {
n i32 = 5
n i32 := 5
defer n = 999
yield n
} else {
@@ -123,7 +123,7 @@ loop_none func() i32 {
# Labeled `while` value loop (label follows the `: update` clause).
loop_while func() i32 {
n i32 = 0
n i32 := 0
found :: while n < 100 : n += 1 blk: {
if (n == 8) yield :blk n
yield null
@@ -199,7 +199,7 @@ lblock func(sel i32) i32 {
# the block's defer runs.
lblock_defer func() i32 {
r :: blk: {
n i32 = 5
n i32 := 5
defer n = 999
if (true) yield :blk n
yield :blk 0
@@ -235,7 +235,7 @@ yield_outer func(target i32) i32 {
# Plain `break :outer` exits an outer loop from an inner loop.
break_outer func() i32 {
count i32 = 0
count i32 := 0
for 0..3 |a| outer: {
for 0..3 |b| {
count += 1
@@ -247,7 +247,7 @@ break_outer func() i32 {
# A labeled block *statement* (not a value source): `break :blk` exits it early.
stmt_block func(early i32) i32 {
x i32 = 0
x i32 := 0
blk: {
x = 1
if (early == 1) break :blk
@@ -259,7 +259,7 @@ stmt_block func(early i32) i32 {
# `break :search` escapes a nested loop and the block in one jump; the block's
# defer still runs on the way out.
stmt_block_escape func() i32 {
hits i32 = 0
hits i32 := 0
search: {
defer hits += 1000
for 0..10 |i| {
@@ -273,7 +273,7 @@ stmt_block_escape func() i32 {
# A labeled block can also be exited through an ordinary nested block.
stmt_block_nested func() i32 {
hits i32 = 0
hits i32 := 0
outer: {
{
hits = 1
+1 -1
View File
@@ -28,7 +28,7 @@ reserve func($T type, list @mut ArrayList(T), min_capacity usize) void ! mem.All
return
}
new_capacity usize = 8
new_capacity usize := 8
if list.capacity >= 8 {
half usize :: divtrunc!(list.capacity, 2)
if list.capacity > maxval!(usize) - half {
+3 -3
View File
@@ -2,7 +2,7 @@ import "@std/mem"
import "@std/testing"
handles_append test {
list ArrayList(i32) = init(mem.c_allocator)
list ArrayList(i32) := init(mem.c_allocator)
defer deinit(&list)
try append(&list, 42)
@@ -12,7 +12,7 @@ handles_append test {
}
handles_clear test {
list ArrayList(i32) = init(mem.c_allocator)
list ArrayList(i32) := init(mem.c_allocator)
defer deinit(&list)
try append(&list, 42)
@@ -22,7 +22,7 @@ handles_clear test {
}
handles_reserve test {
list ArrayList(i32) = init(mem.c_allocator)
list ArrayList(i32) := init(mem.c_allocator)
defer deinit(&list)
try reserve(&list, 10)
+1 -1
View File
@@ -11,7 +11,7 @@ print func($format []u8, $Args type, args Args) void {
}
hide write func(_ ?@mut anyopaque, handle io.Handle, bytes []u8) usize ! io.WriteError {
request usize = bytes.len
request usize := bytes.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
+1 -1
View File
@@ -14,7 +14,7 @@ init func(
$E, $V type,
values meta.EnumFieldStruct(E, ?V, some!(null)),
) EnumMap(E, V) {
map EnumMap(E, V) = undefined
map EnumMap(E, V) := undefined
match typeinfo!(E) {
.enum |info|: inline for info.fields |field, i| {
+1 -1
View File
@@ -8,7 +8,7 @@ TestEnum :: enum(u8) {
}
handles_sparse_enum_get test {
names EnumMap(TestEnum, []u8) = init({
names EnumMap(TestEnum, []u8) := init({
ident = "identifier",
int = "integer",
})
+5 -5
View File
@@ -59,7 +59,7 @@ get func(
if (map.count == 0) return null
hash :: normalize(hash_key(key))
idx usize = hash & (map.entries.len - 1)
idx usize := hash & (map.entries.len - 1)
while true {
entry :: map.entries[idx]
@@ -98,7 +98,7 @@ put func(
if (entry.hash == 0) continue
# find an empty slot
idx usize = entry.hash & (new_entries.len - 1)
idx usize := entry.hash & (new_entries.len - 1)
while new_entries[idx].hash != 0 {
idx = (idx + 1) & (new_entries.len - 1)
}
@@ -112,7 +112,7 @@ put func(
# put new entry
hash :: normalize(hash_key(key))
idx usize = hash & (map.entries.len - 1)
idx usize := hash & (map.entries.len - 1)
while true {
entry :: map.entries[idx]
@@ -144,8 +144,8 @@ hide normalize func(hash usize) usize {
#! FNV-1a hash implementation.
#! note: vulnerable to collision attacks.
hide str_hash func(key []u8) usize {
hash u32 = 2166136261 # offset basis
prime u32 = 16777619
hash u32 := 2166136261 # offset basis
prime u32 := 16777619
for key |byte| {
product u64 :: u64(hash xor u32(byte)) * prime
+1 -1
View File
@@ -2,7 +2,7 @@ import "@std/mem"
import "@std/testing"
handles_put_and_get test {
map StringHashMap(u32) = init(mem.c_allocator)
map StringHashMap(u32) := init(mem.c_allocator)
defer deinit(&map)
try put(&map, "key", 42)
+3 -3
View File
@@ -47,7 +47,7 @@ writer func(file File) Writer {
}
hide system_read func(_ ?@mut anyopaque, handle Handle, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
request usize := buffer.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
@@ -69,7 +69,7 @@ hide system_read func(_ ?@mut anyopaque, handle Handle, buffer []mut u8) usize !
}
hide system_write func(_ ?@mut anyopaque, handle Handle, bytes []u8) usize ! WriteError {
request usize = bytes.len
request usize := bytes.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
@@ -91,7 +91,7 @@ hide system_write func(_ ?@mut anyopaque, handle Handle, bytes []u8) usize ! Wri
}
hide system_open func(_ ?@mut anyopaque, path [;0]u8, mode FileMode) Handle ! OpenError {
flags c_int = c.O_RDONLY
flags c_int := c.O_RDONLY
match mode {
.read_only: flags = c.O_RDONLY
.write_only: flags = c.O_WRONLY
+19 -19
View File
@@ -73,7 +73,7 @@ write func(output Writer, bytes []u8) usize ! WriteError {
}
write_all func(output Writer, bytes []u8) void ! WriteError {
offset usize = 0
offset usize := 0
while offset < bytes.len {
count usize :: write(output, bytes[offset..]) catch |err| {
return err
@@ -129,12 +129,12 @@ print func(output Writer, $format []u8, $Args type, args Args) void ! WriteError
}
hide write_integer_signed func(output Writer, value i64, base u64, uppercase bool) void ! WriteError {
buffer [65]mut u8 = undefined
end usize = buffer.len
current i64 = value
buffer [65]mut u8 := undefined
end usize := buffer.len
current i64 := value
while true {
digit_value i64 :: rem!(current, i64(base))
digit u8 = 0
digit u8 := 0
if digit_value < 0 {
digit = u8(-digit_value)
} else {
@@ -162,9 +162,9 @@ hide write_integer_signed func(output Writer, value i64, base u64, uppercase boo
}
hide write_integer_unsigned func(output Writer, value u64, base u64, uppercase bool) void ! WriteError {
buffer [65]mut u8 = undefined
end usize = buffer.len
current u64 = value
buffer [65]mut u8 := undefined
end usize := buffer.len
current u64 := value
while true {
digit u8 :: u8(rem!(current, base))
end -= 1
@@ -206,11 +206,11 @@ hide FormatToken :: struct {
}
hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
tokens [N]mut FormatToken = undefined
tokens [N]mut FormatToken := undefined
for (usize(0))..format.len |index| {
tokens[index] = FormatToken {kind = .unused, start = 0, end = 0, field = ""}
}
field_count usize = 0
field_count usize := 0
match typeinfo!(Args) {
.record |record|: {
if !record.is_tuple {
@@ -221,10 +221,10 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
else: compile_error!("io.print arguments must be a tuple")
}
token_count usize = 0
argument_count usize = 0
literal_start usize = 0
cursor usize = 0
token_count usize := 0
argument_count usize := 0
literal_start usize := 0
cursor usize := 0
while cursor < format.len {
byte :: format[cursor]
if byte == '{' {
@@ -243,8 +243,8 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
literal_start = cursor
continue
}
kind FormatTokenKind = .default
width usize = 2
kind FormatTokenKind := .default
width usize := 2
if next != '}' {
if cursor + 2 >= format.len or format[cursor + 2] != '}' {
compile_error!("io.print format expects a one-character specifier")
@@ -353,8 +353,8 @@ hide write_integer func(output Writer, $T type, value T, base u64, uppercase boo
hide write_float func(output Writer, $T type, value T, scientific bool) void ! WriteError {
match typeinfo!(T) {
.float: {
buffer [64]mut u8 = undefined
count c_int = 0
buffer [64]mut u8 := undefined
count c_int := 0
if sizeof!(T) == 4 {
if scientific {
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.8e", value)
@@ -401,7 +401,7 @@ hide write_character func(output Writer, $T type, value T) void ! WriteError {
if minval!(T) < 0 or maxval!(T) > 255 {
compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
}
buffer [1]u8 = [u8(value)]
buffer [1]u8 := [u8(value)]
try write_all(output, buffer[..])
}
.distinct |backing|: if scalar_or_distinct_type(backing) {
+11 -11
View File
@@ -46,7 +46,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
return .out_of_memory
}
memory ?*mut u8 = raw_alloc(allocator, count * element_size, alignof!(T))
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
if memory |bytes| {
pointer *mut T :: ptrcast!(T, bytes)
return pointer[..count]
@@ -75,13 +75,13 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
return .out_of_memory
}
old_memory ?*mut u8 = null
old_size usize = 0
old_memory ?*mut u8 := null
old_size usize := 0
if memory.len != 0 {
old_memory = ptrcast!(u8, memory.ptr)
old_size = memory.len * element_size
}
resized ?*mut u8 = raw_realloc(
resized ?*mut u8 := raw_realloc(
allocator,
old_memory,
old_size,
@@ -119,15 +119,15 @@ empty func($T type) []mut T {
return empty_slice(T, 0)
}
hide empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 := [0]
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide power_of_two func(value usize) bool {
if (value == 0) return false
current usize = value
current usize := value
while current > 1 {
half usize = divtrunc!(current, 2)
half usize := divtrunc!(current, 2)
if (half * 2 != current) return false
current = half
}
@@ -141,8 +141,8 @@ hide c_alloc func(_ ?@mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
memory [1]mut ?*mut anyopaque = [null]
status c_int = c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
memory [1]mut ?*mut anyopaque := [null]
status c_int := c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
if (status != 0) return null
return ptrcast!(u8, memory[0])
@@ -161,9 +161,9 @@ hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = c_alloc(null, new_size, alignment)
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
copy_size usize := old_size
if (new_size < copy_size) copy_size = new_size
memcopy!(new_bytes[..copy_size], old_memory[..copy_size])
c.free(old_memory)
+3 -3
View File
@@ -46,9 +46,9 @@ TypeInfo :: union(enum) {
EnumFieldStruct func($E, $Field type, $default ?Field) type {
match typeinfo!(E) {
.enum |info|: {
names [info.fields.len]mut []u8 = undefined
field_types [info.fields.len]mut type = undefined
defaults [info.fields.len]mut ?Field = undefined
names [info.fields.len]mut []u8 := undefined
field_types [info.fields.len]mut type := undefined
defaults [info.fields.len]mut ?Field := undefined
inline for info.fields |field, index| {
names[index] = field.name
field_types[index] = Field
+2 -2
View File
@@ -42,7 +42,7 @@ distinct_reflection_exposes_immediate_backing test {
enum_field_struct_defaults test {
names TestNames = {
names TestNames := {
ident = "identifier",
int = "integer",
}
@@ -60,7 +60,7 @@ enum_field_struct_defaults test {
try testing.expect(false)
}
empty TestNames = {}
empty TestNames := {}
if field!(empty, "ident") |_| {
try testing.expect(false)
}
+8 -8
View File
@@ -19,8 +19,8 @@ init func($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
compile_error!("static string map has too many entries")
}
keys [N]mut []u8 = undefined
values [N]mut V = undefined
keys [N]mut []u8 := undefined
values [N]mut V := undefined
# assert no duplicate keys
for entries |entry, i| {
@@ -37,7 +37,7 @@ init func($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
}
if N == 0 {
len_indexes [0]u32 = undefined
len_indexes [0]u32 := undefined
return StaticStringMap(V){
keys = keys[..],
values = values[..],
@@ -51,7 +51,7 @@ init func($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
for 1..N |i| {
key :: keys[i]
value :: values[i]
j usize = i
j usize := i
while j > 0 and keys[j - 1].len > key.len : j -= 1 {
keys[j] = keys[j - 1]
values[j] = values[j - 1]
@@ -62,8 +62,8 @@ init func($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
min_len u32 :: u32(keys[0].len)
max_len u32 :: u32(keys[N - 1].len)
len_indexes [usize(max_len) + 1]mut u32 = undefined
entry_index usize = 0
len_indexes [usize(max_len) + 1]mut u32 := undefined
entry_index usize := 0
for 0..=usize(max_len) |length| {
while entry_index < N and keys[entry_index].len < length : entry_index += 1 {}
len_indexes[length] = u32(entry_index)
@@ -81,10 +81,10 @@ init func($V type, $N usize, $entries [N]Pair(V)) StaticStringMap(V) {
get func($V type, map @StaticStringMap(V), key []u8) ?V {
if (map.keys.len == 0 or key.len > maxval!(u32)) return null
length u32 = u32(key.len)
length u32 := u32(key.len)
if (length < map.min_len or length > map.max_len) return null
idx usize = usize(map.len_indexes[usize(length)])
idx usize := usize(map.len_indexes[usize(length)])
while idx < map.keys.len : idx += 1 {
candidate :: map.keys[idx]
if (candidate.len != key.len) return null
+11 -11
View File
@@ -77,8 +77,8 @@ read_command func() Command {
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) return .spawn{ GetMousePosition() }
if IsKeyPressed(KEY_SPACE) return .clear
fx f32 = 0.0
fy f32 = 0.0
fx f32 := 0.0
fy f32 := 0.0
if IsKeyDown(KEY_A) fx -= FORCE
if IsKeyDown(KEY_D) fx += FORCE
if IsKeyDown(KEY_W) fy -= FORCE
@@ -128,14 +128,14 @@ step func(b @mut Ball) void {
draw_ball func(b @Ball, highlight bool) void {
col :: color_for(b.kind)
center Vector2 = Vector2{ x = b.x, y = b.y }
center Vector2 := Vector2{ x = b.x, y = b.y }
match b.kind {
.circle: DrawCircleV(center, b.radius, col)
.square: DrawPoly(center, 4, b.radius, 45.0, col)
.triangle: DrawPoly(center, 3, b.radius, 0.0, col)
}
if highlight {
ring Color = Color{ r = 250, g = 245, b = 200, a = 255 }
ring Color := Color{ r = 250, g = 245, b = 200, a = 255 }
DrawPoly(center, 24, b.radius + RING_PAD, 0.0, ring)
}
}
@@ -150,11 +150,11 @@ main func() i32 {
`[click] spawn a shape [WASD/arrows] blow wind
`[space] clear
balls [CAP]mut Ball = undefined
count usize = 0 # number of live balls, in slots 0..count
kc Kind = .circle # next kind to spawn
spin f32 = 1.0 # rotates spawn velocity for variety
at_cap bool = false # show the "at capacity" banner
balls [CAP]mut Ball := undefined
count usize := 0 # number of live balls, in slots 0..count
kc Kind := .circle # next kind to spawn
spin f32 := 1.0 # rotates spawn velocity for variety
at_cap bool := false # show the "at capacity" banner
bg :: Color{ r = 24, g = 26, b = 34, a = 255 }
text :: Color{ r = 225, g = 225, b = 230, a = 255 }
@@ -209,7 +209,7 @@ main func() i32 {
# --- which shape is under the cursor? (optional via a value-loop) ---
mouse :: GetMousePosition()
sel :: for 0..(count) |i| blk: {
c Vector2 = Vector2{ x = balls[i].x, y = balls[i].y }
c Vector2 := Vector2{ x = balls[i].x, y = balls[i].y }
if CheckCollisionPointCircle(mouse, c, balls[i].radius) yield :blk i
yield null
}
@@ -220,7 +220,7 @@ main func() i32 {
for (&balls) |@b, i| {
if (i >= count) break
hot bool = false
hot bool := false
if sel |s| {
if (s == i) hot = true # true only for the hovered ball
}
+3 -3
View File
@@ -48,7 +48,7 @@ hide append_token func(tokens @mut std.ArrayList(Token), kind Kind, start, end u
}
lex func(source []u8, tokens @mut std.ArrayList(Token)) void ! mem.AllocError {
cursor usize = 0
cursor usize := 0
while cursor < source.len {
value u8 :: source[cursor]
if value == ' ' or value == '\t' or value == '\r' {
@@ -112,7 +112,7 @@ hide print_token func(source []u8, token Token) void {
_ = c.printf("%-11s", kind_name(token.kind))
if token.length != 0 {
_ = c.printf(" `")
i usize = 0
i usize := 0
while i < token.length : i += 1 {
value u8 :: source[token.start + i]
if value == '\n' {
@@ -132,7 +132,7 @@ main func() i32 {
` hello()
`}
tokens std.ArrayList(Token) = arraylist.init(mem.c_allocator)
tokens std.ArrayList(Token) := arraylist.init(mem.c_allocator)
defer arraylist.deinit(&tokens)
lex(source, &tokens) catch |_| {
+1 -1
View File
@@ -28,7 +28,7 @@ reserve func($T type, list @mut ArrayList(T), minimum_capacity usize) void ! mem
return
}
new_capacity usize = 8
new_capacity usize := 8
if list.capacity >= 8 {
half usize :: divtrunc!(list.capacity, 2)
if list.capacity > maxval!(usize) - half {
+3 -3
View File
@@ -61,7 +61,7 @@ write func(writer Writer, bytes []u8) usize ! WriteError {
}
write_all func(writer Writer, bytes []u8) void ! WriteError {
offset usize = 0
offset usize := 0
while offset < bytes.len {
count usize :: write(writer, bytes[offset..]) catch |err| {
return err
@@ -75,7 +75,7 @@ write_all func(writer Writer, bytes []u8) void ! WriteError {
}
hide system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
request usize := buffer.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
@@ -93,7 +93,7 @@ hide system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usi
hide system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
fd c_int :: c_int(stream)
request usize = bytes.len
request usize := bytes.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
+13 -13
View File
@@ -32,7 +32,7 @@ eql func($T type, left, right []T) bool {
return false
}
i usize = 0
i usize := 0
while i < left.len : i += 1 {
if left[i] != right[i] {
return false
@@ -41,7 +41,7 @@ eql func($T type, left, right []T) bool {
return true
}
hide empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 := [0]
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
@@ -65,7 +65,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
return .out_of_memory
}
memory ?*mut u8 = raw_alloc(allocator, count * element_size, alignof!(T))
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
if memory |bytes| {
pointer *mut T :: ptrcast!(T, bytes)
return pointer[..count]
@@ -90,13 +90,13 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
return .out_of_memory
}
old_memory ?*mut u8 = null
old_size usize = 0
old_memory ?*mut u8 := null
old_size usize := 0
if memory.len != 0 {
old_memory = ptrcast!(u8, memory.ptr)
old_size = memory.len * element_size
}
resized ?*mut u8 = raw_realloc(
resized ?*mut u8 := raw_realloc(
allocator,
old_memory,
old_size,
@@ -123,9 +123,9 @@ hide power_of_two func(value usize) bool {
return false
}
current usize = value
current usize := value
while current > 1 {
half usize = divtrunc!(current, 2)
half usize := divtrunc!(current, 2)
if half * 2 != current {
return false
}
@@ -144,8 +144,8 @@ hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
memory [1]mut ?*mut anyopaque = [null]
status c_int = c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
memory [1]mut ?*mut anyopaque := [null]
status c_int := c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
if status != 0 {
return null
}
@@ -168,13 +168,13 @@ hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = c_alloc(null, new_size, alignment)
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
copy_size usize := old_size
if new_size < copy_size {
copy_size = new_size
}
i usize = 0
i usize := 0
while i < copy_size : i += 1 {
new_bytes[i] = old_memory[i]
}
+4 -4
View File
@@ -25,7 +25,7 @@ tier_bonus func(tier Tier) i32 {
}
projected_score func(player Player) i32 {
total i32 = player.score
total i32 := player.score
total += tier_bonus(player.tier)
if player.active and player.streak > 2 {
total += player.streak * 3
@@ -42,8 +42,8 @@ apply_decay func(players []mut Player) void {
}
best_player func(players []mut Player) ?@mut Player {
best ?@mut Player = null
best_score i32 = 0
best ?@mut Player := null
best_score i32 := 0
for players |@player| {
score :: projected_score(player^)
@@ -62,7 +62,7 @@ best_player func(players []mut Player) ?@mut Player {
}
main func() i32 {
players [4]mut Player = [
players [4]mut Player := [
Player { id = PlayerID(1), name = "Ada", tier = .gold, score = 41, streak = 4, active = true },
Player { id = PlayerID(2), name = "Ken", tier = .silver, score = 56, streak = 1, active = true },
Player { id = PlayerID(3), name = "Edsger", tier = .bronze, score = 64, streak = 0, active = false },
+9 -9
View File
@@ -27,7 +27,7 @@ raw_free func(allocator Allocator, memory ?*mut u8, size usize, alignment usize)
allocator.vtable.free(allocator.context, memory, size, alignment)
}
hide empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 := [0]
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
@@ -47,7 +47,7 @@ alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
return .out_of_memory
}
memory ?*mut u8 = raw_alloc(allocator, count * element_size, alignof!(T))
memory ?*mut u8 := raw_alloc(allocator, count * element_size, alignof!(T))
if memory |bytes| {
pointer *mut T :: ptrcast!(T, bytes)
return pointer[..count]
@@ -68,9 +68,9 @@ hide power_of_two func(value usize) bool {
return false
}
current usize = value
current usize := value
while current > 1 {
half usize = current / 2
half usize := current / 2
if half * 2 != current {
return false
}
@@ -89,8 +89,8 @@ hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
memory [1]mut ?*mut anyopaque = [null]
status c_int = c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
memory [1]mut ?*mut anyopaque := [null]
status c_int := c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
if status != 0 {
return null
}
@@ -113,13 +113,13 @@ hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = c_alloc(null, new_size, alignment)
new_memory ?*mut u8 := c_alloc(null, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
copy_size usize := old_size
if new_size < copy_size {
copy_size = new_size
}
i usize = 0
i usize := 0
while i < copy_size : i += 1 {
new_bytes[i] = old_memory[i]
}