add yield
This commit is contained in:
@@ -305,7 +305,32 @@
|
||||
a bare block is built and spliced inline, and a deferred statement is built once at the
|
||||
`defer` site and its hir replayed at each exit, so lowering/codegen are unchanged
|
||||
|
||||
20. add `yield` statement (see below)
|
||||
20. add `yield` statement (implemented; first pass — value blocks only; see below)
|
||||
- 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
|
||||
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
|
||||
- `yield` is valid *only* as the final statement of a value block. A `yield` nested in an
|
||||
`if`/loop/inner block, or in a non-value block, is rejected ("'yield' is only valid as
|
||||
the final statement of a value block"); a value block not ending in `yield` is rejected
|
||||
too. This no-early-exit restriction keeps it a lexer/parser/checker-only change with no
|
||||
HIR/lowering touch (like milestones 18/19)
|
||||
- new `Keyword_Yield` token + `.Yield` AST stmt (reuses `expr`); a block-initialized
|
||||
`Declaration`/`Assignment` reuses the existing `body` field with `expr` invalid. The
|
||||
checker's `build_value_block` builds the leading statements (via `build_block` with a
|
||||
new `close=false` flag that keeps the scope open), evaluates the final yield, spills and
|
||||
flushes the block's defers, then feeds the value into an ordinary `Declaration`/
|
||||
`Assignment`. HIR never holds a `.Yield` (final yield → `Declaration`/`Assignment`,
|
||||
misplaced yield → `Trap`), so lowering/codegen are unchanged
|
||||
- deferred to a later milestone (needs labeled blocks + rules for whether an `if`/loop
|
||||
always produces a value, e.g. optionals): yield from inside `if`/loops, labeled blocks
|
||||
(`blk: { yield :blk v }`), implicit trailing-expression yield, and yield in match arms /
|
||||
`catch` handlers (milestones 21–22)
|
||||
|
||||
20.5 `yield` from if-statements and loops (see below)
|
||||
|
||||
21. unions and tagged unions
|
||||
|
||||
@@ -546,6 +571,59 @@ data []u8 = read(path) catch |e| {
|
||||
}
|
||||
```
|
||||
|
||||
### Yielding from if-statements and loops
|
||||
|
||||
Yielding from if-statements is possible with the constraint that all branches must resolve to the same yield type.
|
||||
|
||||
```
|
||||
# yielding to a constant
|
||||
result :: if a {
|
||||
yield 1
|
||||
} else if b {
|
||||
yield 2
|
||||
} else {
|
||||
yield 3
|
||||
}
|
||||
|
||||
# yielding to a variable
|
||||
result int = if a {
|
||||
yield 1
|
||||
} else if b {
|
||||
yield 2
|
||||
} else {
|
||||
yield 3
|
||||
}
|
||||
|
||||
# ILLEGAL: branches with different yield types
|
||||
result :: if a {
|
||||
yield 1
|
||||
} else {
|
||||
yield Color{ r = 255, g = 0, b = 0 }
|
||||
}
|
||||
```
|
||||
|
||||
Yielding is also possible from loops with the same constraint.
|
||||
|
||||
```
|
||||
# get active entity
|
||||
active_ent_idx :: for 0..10 |i| blk: {
|
||||
if is_active(some_entity, i) yield :blk i
|
||||
|
||||
# note that in this case, we have to use the `blk` label to yield from the correct scope.
|
||||
# otherwise, the yield should return directly from the if-statement's scope (which would be incorrect in this case).
|
||||
}
|
||||
|
||||
# BAD: yield returned from if-statement, but no name binds it: should miscompile similar to unused return values from functions.
|
||||
active_ent_idx :: for 0..10 |i| {
|
||||
if is_active(some_entity, i) yield i # bad
|
||||
}
|
||||
|
||||
# BAD: likewise for loops
|
||||
for 0..10 |i| blk: { # bad, no name binds returned value
|
||||
if is_active(some_entity, i) yield :blk i
|
||||
}
|
||||
```
|
||||
|
||||
## A word on memory allocation
|
||||
|
||||
(NOTE THAT SYNTAX MAY NOT MATCH BROLANG EXACTLY AND SHOULD BE TAKEN WITH A GRAIN OF SALT - INSPIRATION ONLY)
|
||||
|
||||
Reference in New Issue
Block a user