diff --git a/LANGUAGE.md b/LANGUAGE.md index 2423e3a..a6784b2 100644 --- a/LANGUAGE.md +++ b/LANGUAGE.md @@ -117,13 +117,13 @@ fields. `_` is not a keyword member name. - field access through struct values and pointers, index/slice bounds contextually coerced to `usize`, and unsigned narrower index support - boolean `if` / `else if` / `else` and `for` loops with braceless single-statement bodies when the preceding expression is parenthesized or a function call - `while` loops with optional post-iteration update clauses -- `for` loops over ranges, arrays, slices, and pointers-to-arrays with copy captures, pointer captures `|@item|`, and optional `usize` index captures; `expand for` specializes a comptime aggregate into one checked body per element +- `for` loops over ranges, arrays, slices, and pointers-to-arrays with copy captures, pointer captures `|@item|`, and optional `usize` index captures; `inline for` specializes a comptime aggregate into one checked body per element - `break`, `continue`, labeled `break :label`, labeled `continue :label`, and labeled plain blocks; `break :label` can cross nested scopes to exit a labeled block - bare block scopes, `defer`, and fallible-function `errdefer` with optional error capture; cleanup is block-scoped and LIFO - always-trapping `unreachable`, a `noreturn` expression that diagnoses use during comptime evaluation and terminates the current runtime path - bare void `return`, same-line `return value`, value blocks, value `if` with implicit single-expression branches, value loops, value `match`, and strictly value-producing `yield value` / `yield :label value` - `match` statements/expressions over enums, tagged unions, and scalars, including exhaustiveness checks, payload captures, pointer payload captures, multi-pattern arms, and scalar range patterns -- a final `expand |value|:` enum arm or `expand |payload[, tag]|:` tagged-union arm generates one specialized arm for each variant not covered earlier; enum values and optional tags are comptime-known, while union payloads keep their concrete variant type +- a final `inline |value|:` enum arm or `inline |payload[, tag]|:` tagged-union arm generates one specialized arm for each variant not covered earlier; enum values and optional tags are comptime-known, while union payloads keep their concrete variant type - fallible `try` and uniform `catch [|e|] value_source` fallbacks; captures work with ordinary expressions, value blocks, and value-producing `if` / loops / `match` - direct `return match ...` and `yield match ...` value-control-flow operands @@ -238,7 +238,7 @@ exactly once. Bare functions named `memcopy` or `memset` remain ordinary user fu - `some!(value)` explicitly constructs the present branch of an expected optional, including nested optionals where `some!(null)` differs from outer `null` - tuple types are unnamed-field structs (`struct { i32, []u8 }`), tuple values use `{1, "bro"}` / `{1,}` / `{}`, and fields use canonical numeric names such as `.0` - anonymous keyed records use `{x = 1, name = "bro"}`; without context their declaration-ordered names and inferred value types form a structurally interned record type, while a record context applies that type's coercions and field defaults; `{}` remains an empty tuple without context and constructs an empty contextual record when a record is expected -- `typeinfo!`, `field!`, `compile_error!`, and semantic `expand for` provide compile-time record and enum reflection and heterogeneous static expansion without runtime metadata; enum reflection exposes declaration-ordered fields, reflected aggregates remain persistent compile-time values, and expand-loop `break` / `continue` must be selected entirely at comptime +- `typeinfo!`, `field!`, `compile_error!`, and semantic `inline for` provide compile-time record and enum reflection and heterogeneous static expansion without runtime metadata; enum reflection exposes declaration-ordered fields, reflected aggregates remain persistent compile-time values, and inline-loop `break` / `continue` must be selected entirely at comptime - `tag!(value)` reads a tagged union's active discriminant and folds when the value is comptime-known; `tagname!(enum_value)` requires a comptime-known enum value and returns its immutable declaration name - bodyful `c_func` definitions and bodyless `c_func` declarations with exact external symbol names - concrete-only C signatures, C variadic declarations/calls, and C default argument promotions diff --git a/TODO.md b/TODO.md index 309028c..6059a5d 100644 --- a/TODO.md +++ b/TODO.md @@ -856,8 +856,8 @@ - tuples are unnamed-field structs with structural anonymous values, nominal named declarations, brace literals, numeric fields, and no runtime metadata - `@std/meta`, `typeinfo!`, `field!`, `compile_error!`, specialization-time branches, and semantic - `expand for` use checker-owned persistent compile-time values for aggregate-first reflection and - heterogeneous static expansion; expand-loop control is recursively resolved at comptime + `inline for` use checker-owned persistent compile-time values for aggregate-first reflection and + heterogeneous static expansion; inline-loop control is recursively resolved at comptime - interleaved comptime parameters use semantic candidate resolution, immutable byte values specialize by contents, and all comptime parameters remain erased from the runtime ABI - `io.print(writer, format, args)` validates and expands `{s}` / `{d}` formatting at comptime, @@ -890,10 +890,9 @@ - integer output uses one base-aware 65-byte stack buffer; float output uses fixed-buffer libc `snprintf` with 32-bit and 64-bit general/scientific precision and propagates failure -40. compile-time `expand` (implemented) - - expansion-oriented `inline for` is strictly renamed to `expand for`; `inline` remains available - for future function-inlining syntax - - final expanded enum and tagged-union match arms generate checker-local specialized arms only +40. compile-time `inline` (implemented) + - expansion-oriented `expand for` is strictly renamed to `inline for`; `expand` is no longer a keyword + - final inlined enum and tagged-union match arms generate checker-local specialized arms only for variants not covered by preceding explicit arms - generated enum values and union tags are static bindings, heterogeneous payloads retain their concrete types, and `void` payloads support value and pointer captures without runtime storage diff --git a/compiler/ast/ast.odin b/compiler/ast/ast.odin index 6d5e82d..908124a 100644 --- a/compiler/ast/ast.odin +++ b/compiler/ast/ast.odin @@ -221,7 +221,7 @@ Stmt :: struct { // list (empty marks the `else` arm; more than one is a multi-pattern arm), // `captures` for the optional payload capture (0 or 1 name, tagged-union variants // only) with `pointer_capture` distinguishing `|@cap|` from `|cap|`, and `body` - // as the arm body. An expanded arm has `expand` set, no patterns, and one or two + // as the arm body. An `inline` arm has `expand` set, no patterns, and one or two // captures for its specialized value/payload and optional tagged-union tag. captures: []symbol.Id, // `Match_Arm` pattern list; empty ⇒ the `else` arm. diff --git a/compiler/checker/checker.odin b/compiler/checker/checker.odin index 9f67486..46a8d17 100644 --- a/compiler/checker/checker.odin +++ b/compiler/checker/checker.odin @@ -10574,7 +10574,7 @@ expand_field_bindings :: proc( value := state.values[value_id] if ct_value_contains_undefined(&state, value_id) { if diagnose { - _ = ct_fail(&state, .Not_Comptime, checker.ast_module.exprs[expr].span, "expand for cannot expand an undefined comptime value") + _ = ct_fail(&state, .Not_Comptime, checker.ast_module.exprs[expr].span, "inline for cannot iterate an undefined comptime value") } return nil, .Diagnosed if state.diagnostic != source.INVALID_DIAGNOSTIC else .Invalid } @@ -10712,7 +10712,7 @@ contains_expand_control :: proc( } case .For, .While: // Unlabelled control belongs to the nested loop. A labelled jump can still - // name the surrounding expand loop and is therefore relevant here. + // name the surrounding inline loop and is therefore relevant here. if contains_expand_control(checker, statement.body, target_label, false) { return true } @@ -10817,7 +10817,7 @@ flatten_expand_iteration :: proc( if diagnostic != nil { diagnostic^ = source.add( checker.diagnostics, statement.span, - "break or continue targeting an expand loop must be compile-time-resolvable", + "break or continue targeting an inline loop must be compile-time-resolvable", ) } return .Invalid @@ -10856,7 +10856,7 @@ flatten_expand_iteration :: proc( if diagnostic != nil { diagnostic^ = source.add( checker.diagnostics, statement.span, - "break or continue targeting an expand loop must be compile-time-resolvable", + "break or continue targeting an inline loop must be compile-time-resolvable", ) } return .Invalid @@ -10882,7 +10882,7 @@ flatten_expand_iteration :: proc( if diagnostic != nil { diagnostic^ = source.add( checker.diagnostics, statement.span, - "break or continue targeting an expand loop must be compile-time-resolvable", + "break or continue targeting an inline loop must be compile-time-resolvable", ) } return .Invalid @@ -11814,7 +11814,7 @@ build_block :: proc( case .For: if statement.expand { if statement.pointer_capture { - id := source.add(checker.diagnostics, statement.span, "expand for does not support pointer captures") + id := source.add(checker.diagnostics, statement.span, "inline for does not support pointer captures") append(&body, hir.stmt_id(len(checker.module.statements))) append(&checker.module.statements, hir.Stmt{kind=.Trap, span=statement.span, diagnostic=id}) ctx.problematic^ = true @@ -11822,9 +11822,9 @@ build_block :: proc( } bindings, expand_error := expand_field_bindings(checker, statement.expr, statement.name, ctx.pkg, ctx.file, true) if expand_error != .None && expand_error != .Diagnosed { - message := "expand for requires a comptime tuple, fixed array, range, slice, or reflection value" + message := "inline for requires a comptime tuple, fixed array, range, slice, or reflection value" if expand_error == .Quota { - message = "expand for expansion exceeds the compile-time evaluation quota" + message = "inline for expansion exceeds the compile-time evaluation quota" } id := source.add( checker.diagnostics, statement.span, @@ -12869,28 +12869,28 @@ emit_match :: proc( continue } if has_else || has_expand { - message := "arms after 'else' are unreachable" if has_else else "arms after 'expand' are unreachable" + message := "arms after 'else' are unreachable" if has_else else "arms after 'inline' are unreachable" source.add(checker.diagnostics, arm.span, message) ok = false } if arm.expand { if !is_tagged && !is_enum_subject { - source.add(checker.diagnostics, arm.span, "'expand' requires an enum or tagged-union match subject") + source.add(checker.diagnostics, arm.span, "'inline' requires an enum or tagged-union match subject") ok = false continue } expected_captures := 1 if is_enum_subject else 2 if len(arm.captures) == 0 || len(arm.captures) > expected_captures { description := "exactly one capture" if is_enum_subject else "one or two captures" - source.addf(checker.diagnostics, arm.span, "expanded match on '%s' requires %s", type_label(checker, subject_type), description) + source.addf(checker.diagnostics, arm.span, "inlined match on '%s' requires %s", type_label(checker, subject_type), description) ok = false } if is_enum_subject && arm.pointer_capture { - source.add(checker.diagnostics, arm.span, "enum expansion does not support pointer captures") + source.add(checker.diagnostics, arm.span, "enum inlining does not support pointer captures") ok = false } if len(arm.captures) > 1 && arm.captures[0] != checker.sink_symbol && arm.captures[0] == arm.captures[1] { - source.add(checker.diagnostics, arm.span, "expand captures must have distinct names") + source.add(checker.diagnostics, arm.span, "inline captures must have distinct names") ok = false } remaining := 0 @@ -12963,7 +12963,7 @@ emit_match :: proc( } } if remaining == 0 { - source.add(checker.diagnostics, arm.span, "redundant 'expand': the 'match' already covers every variant") + source.add(checker.diagnostics, arm.span, "redundant 'inline': the 'match' already covers every variant") ok = false } has_expand = true diff --git a/compiler/lexer/lexer.odin b/compiler/lexer/lexer.odin index 0bb3541..4961087 100644 --- a/compiler/lexer/lexer.odin +++ b/compiler/lexer/lexer.odin @@ -40,7 +40,7 @@ keyword_kind :: proc(text: string) -> token.Kind { case "if": return .Keyword_If case "while": return .Keyword_While case "for": return .Keyword_For - case "expand": return .Keyword_Expand + case "inline": return .Keyword_Inline case "break": return .Keyword_Break case "continue": return .Keyword_Continue case "defer": return .Keyword_Defer diff --git a/compiler/parser/parser.odin b/compiler/parser/parser.odin index fb49343..e39bd75 100644 --- a/compiler/parser/parser.odin +++ b/compiler/parser/parser.odin @@ -1813,16 +1813,7 @@ parse_value_control_flow :: proc(parser: ^Parser) -> (ast.Stmt_Id, bool) { } parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id { - if current(parser).kind == .Identifier && token_text(parser, current(parser)) == "inline" && - peek(parser).kind == .Keyword_For { - start := advance(parser) - id := parse_for(parser) - parser.module.statements[id].expand = true - parser.module.statements[id].span = span_from(start.span, parser.module.statements[id].span) - source.add(parser.diagnostics, start.span, "'inline for' was renamed to 'expand for'") - return id - } - if current(parser).kind == .Keyword_Expand && peek(parser).kind == .Keyword_For { + if current(parser).kind == .Keyword_Inline && peek(parser).kind == .Keyword_For { start := advance(parser) id := parse_for(parser) parser.module.statements[id].expand = true @@ -2266,7 +2257,7 @@ parse_arm_body :: proc(parser: ^Parser) -> []ast.Stmt_Id { } // parse_match_arm parses one ` [|[@]capture|]: `, `else: `, -// or `expand |[@]value[, tag]|: ` arm. +// or `inline |[@]value[, tag]|: ` arm. parse_match_arm :: proc(parser: ^Parser) -> ast.Stmt_Id { start := current(parser).span patterns: [dynamic]ast.Expr_Id @@ -2275,10 +2266,10 @@ parse_match_arm :: proc(parser: ^Parser) -> ast.Stmt_Id { captures.allocator = parser.module.allocator pointer_capture := false expand := false - if _, is_expand := allow(parser, .Keyword_Expand); is_expand { + if _, is_expand := allow(parser, .Keyword_Inline); is_expand { expand = true if _, ok := allow(parser, .Pipe); !ok { - source.add(parser.diagnostics, current(parser).span, "expected '|' before expand captures") + source.add(parser.diagnostics, current(parser).span, "expected '|' before inline captures") } else { if _, at_ok := allow(parser, .At); at_ok { pointer_capture = true @@ -2288,7 +2279,7 @@ parse_match_arm :: proc(parser: ^Parser) -> ast.Stmt_Id { advance(parser) append(&captures, name_tok.symbol) } else { - source.add(parser.diagnostics, current(parser).span, "expected an expand value capture") + source.add(parser.diagnostics, current(parser).span, "expected an inline value capture") } if _, comma_ok := allow(parser, .Comma); comma_ok { tag_tok := current(parser) @@ -2296,10 +2287,10 @@ parse_match_arm :: proc(parser: ^Parser) -> ast.Stmt_Id { advance(parser) append(&captures, tag_tok.symbol) } else { - source.add(parser.diagnostics, current(parser).span, "expected an expand tag capture") + source.add(parser.diagnostics, current(parser).span, "expected an inline tag capture") } if _, extra := allow(parser, .Comma); extra { - source.add(parser.diagnostics, current(parser).span, "'expand' accepts at most two captures") + source.add(parser.diagnostics, current(parser).span, "'inline' accepts at most two captures") for current(parser).kind != .Pipe && current(parser).kind != .Colon && current(parser).kind != .Newline && current(parser).kind != .Eof { advance(parser) @@ -2307,7 +2298,7 @@ parse_match_arm :: proc(parser: ^Parser) -> ast.Stmt_Id { } } if _, close_ok := allow(parser, .Pipe); !close_ok { - source.add(parser.diagnostics, current(parser).span, "expected '|' to close expand captures") + source.add(parser.diagnostics, current(parser).span, "expected '|' to close inline captures") } } } else if _, is_else := allow(parser, .Keyword_Else); !is_else { diff --git a/compiler/token/token.odin b/compiler/token/token.odin index bd34c25..64c0404 100644 --- a/compiler/token/token.odin +++ b/compiler/token/token.odin @@ -85,7 +85,7 @@ Kind :: enum u8 { Keyword_If, Keyword_While, Keyword_For, - Keyword_Expand, + Keyword_Inline, Keyword_Break, Keyword_Continue, Keyword_Defer, diff --git a/compiler_tests.odin b/compiler_tests.odin index 2cc98f5..f9aaeae 100644 --- a/compiler_tests.odin +++ b/compiler_tests.odin @@ -177,6 +177,21 @@ lexer_preserves_newlines_and_skips_comments :: proc(t: ^testing.T) { testing.expect_value(t, stream.items[1].kind, token.Kind.Identifier) } +@(test) +inline_is_keyword_and_expand_is_identifier :: proc(t: ^testing.T) { + source_file := source.Source{path="test.bro", text="inline expand"} + diagnostics := source.init_diagnostics(&source_file) + defer source.destroy_diagnostics(&diagnostics) + symbols := symbol.init_table() + defer symbol.destroy_table(&symbols) + stream := lexer.lex(&source_file, &diagnostics, &symbols) + defer delete(stream.items) + + testing.expect_value(t, len(diagnostics.items), 0) + testing.expect_value(t, stream.items[0].kind, token.Kind.Keyword_Inline) + testing.expect_value(t, stream.items[1].kind, token.Kind.Identifier) +} + @(test) lexer_recognizes_bitwise_operators_with_longest_match :: proc(t: ^testing.T) { source_file := source.Source{path="test.bro", text="~ & &= | |= xor xor= << <<= >> >>= <<| <<|= ^"} @@ -1253,6 +1268,45 @@ main func() void { testing.expect(t, !found_old_function_error) } +@(test) +function_signature_context_infers_enum_literals :: proc(t: ^testing.T) { + text := `TokenKind :: enum { + ident + double_colon + newline +} +ParseError :: enum { + unexpected_token +} +parse func() void ! ParseError { + try expect(.ident) + try expect(.double_colon) + try expect(.newline) +} +expect func(kind TokenKind) void ! ParseError { + if kind == .newline { + return .unexpected_token + } +} +main func() void { + parse() catch |_| {} +} +` + source_file := source.Source{path="test.bro", text=text} + diagnostics := source.init_diagnostics(&source_file) + defer source.destroy_diagnostics(&diagnostics) + symbols := symbol.init_table() + defer symbol.destroy_table(&symbols) + stream := lexer.lex(&source_file, &diagnostics, &symbols) + defer delete(stream.items) + ast_module := parser.parse(&stream, &source_file, &diagnostics) + defer ast.destroy_module(&ast_module) + hir_module := checker.check(&ast_module, &diagnostics, &symbols) + defer hir.destroy_module(&hir_module) + + testing.expect_value(t, len(diagnostics.items), 0) +} + @(test) pipeline_emits_specialized_calling_conventions_and_checked_add :: proc(t: ^testing.T) { text := `sum_c c_func(a, b int) int { @@ -3236,10 +3290,10 @@ milestone_37_tuples_reflection_expand_for_and_debug_print_compile_and_run :: pro @(test) expanded_matches_and_tag_intrinsics_compile_and_run :: proc(t: ^testing.T) { - output := "/tmp/brolang-test-expand" + output := "/tmp/brolang-test-inline" defer _ = os.remove(output) status := compiler_core.compile_package( - "examples/programs/expand", output, nil, target.DEFAULT, cimport.Options{}, ".", + "examples/programs/inline", output, nil, target.DEFAULT, cimport.Options{}, ".", ) testing.expect_value(t, status, 0) state, stdout, stderr, _ := os2.process_exec( @@ -3261,29 +3315,29 @@ main func() void { inline for {1} |value| { _ = value } n i32 = 1 - match n { expand |value|: _ = value } + match n { inline |value|: _ = value } e E = .a - match e { expand |value, tag|: _ = value } + match e { inline |value, tag|: _ = value } match e { .a, .b: {} - expand |value|: _ = value + inline |value|: _ = value } match e { - expand |value|: _ = value + inline |value|: _ = value .b: {} } match e { else: {} - expand |value|: _ = value + inline |value|: _ = value } u Plain = Plain{value = 1} _ = tag!(u) _ = tagname!(e) - match e { expand ||: {} } - match e { expand |a, b, c|: {} } + match e { inline ||: {} } + match e { inline |a, b, c|: {} } } ` source_file := source.Source{path="expand_diagnostics.bro", text=text} @@ -3298,7 +3352,6 @@ main func() void { hir_module := checker.check(&ast_module, &diagnostics, &symbols) defer hir.destroy_module(&hir_module) - found_old := false found_subject := false found_captures := false found_redundant := false @@ -3309,17 +3362,15 @@ main func() void { found_tagname := false for diagnostic in diagnostics.items { message := diagnostic.message - found_old = found_old || strings.contains(message, "'inline for' was renamed to 'expand for'") - found_subject = found_subject || strings.contains(message, "'expand' requires an enum or tagged-union") + found_subject = found_subject || strings.contains(message, "'inline' requires an enum or tagged-union") found_captures = found_captures || strings.contains(message, "requires exactly one capture") - found_redundant = found_redundant || strings.contains(message, "redundant 'expand'") - found_after = found_after || strings.contains(message, "arms after 'expand' are unreachable") || strings.contains(message, "arms after 'else' are unreachable") - found_missing = found_missing || strings.contains(message, "expected an expand value capture") + found_redundant = found_redundant || strings.contains(message, "redundant 'inline'") + found_after = found_after || strings.contains(message, "arms after 'inline' are unreachable") || strings.contains(message, "arms after 'else' are unreachable") + found_missing = found_missing || strings.contains(message, "expected an inline value capture") found_many = found_many || strings.contains(message, "at most two captures") found_tag = found_tag || strings.contains(message, "tag! requires a tagged-union value") found_tagname = found_tagname || strings.contains(message, "tagname! requires a comptime-known enum value") } - testing.expect(t, found_old) testing.expect(t, found_subject) testing.expect(t, found_captures) testing.expect(t, found_redundant) @@ -3751,7 +3802,7 @@ main func() i32 { return answer } milestone_37_expand_loop_control_must_be_statically_resolvable :: proc(t: ^testing.T) { text := `main func() void { total i32 = 0 - expand for {1, 2} |value| { + inline for {1, 2} |value| { if total == 0 { break } @@ -3775,7 +3826,7 @@ milestone_37_expand_loop_control_must_be_statically_resolvable :: proc(t: ^testi for diagnostic in diagnostics.items { found = found || strings.contains( diagnostic.message, - "break or continue targeting an expand loop must be compile-time-resolvable", + "break or continue targeting an inline loop must be compile-time-resolvable", ) } testing.expect(t, found) @@ -3803,7 +3854,7 @@ read_initialized_sibling func() i32 { answer :: $read_initialized_sibling() main func() i32 { total usize = 0 - expand for make_tokens() |token| { + inline for make_tokens() |token| { total += token.text.len + token.count } if answer != 42 or total != 8 { @@ -3884,8 +3935,8 @@ milestone_37_expand_expansions_keep_distinct_call_resolutions :: proc(t: ^testin } main func() i32 { total i64 = 0 - expand for {{i8(1), i16(2)}, {i32(3), i64(4)}} |row| { - expand for row |value| { + inline for {{i8(1), i16(2)}, {i32(3), i64(4)}} |row| { + inline for row |value| { total += i64(identity(value)) } } @@ -3917,13 +3968,13 @@ main func() i32 { milestone_37_expand_control_prunes_inference_after_static_exit :: proc(t: ^testing.T) { text := `take_i8 func(value i8) void { _ = value } main func() void { - expand for {i8(1), "skip"} |value, index| { + inline for {i8(1), "skip"} |value, index| { if index == 1 { continue } take_i8(value) } - expand for {i8(1), "stop"} |value, index| { + inline for {i8(1), "stop"} |value, index| { if index == 1 { break } @@ -3954,7 +4005,7 @@ StringToken :: struct { kind Kind, value []u8 } StopToken :: struct { kind Kind, value bool } take_i8 func(value i8) void { _ = value } main func() void { - expand for { + inline for { IntToken {kind = .integer, value = 1}, StringToken {kind = .string, value = "ok"}, StopToken {kind = .stop, value = false}, @@ -3968,7 +4019,7 @@ main func() void { .stop: break } } - expand for {i8(2), "skip", "stop"} |value, index| { + inline for {i8(2), "skip", "stop"} |value, index| { match index { 0: {} 1..=1, 7: continue @@ -6742,7 +6793,7 @@ via_nested func() i32 ! AError { via_expand func() i32 ! AError { abc(1) catch |err| { match err { - expand |tag|: match tag { + inline |tag|: match tag { .a: return err else: unreachable } @@ -15247,7 +15298,7 @@ Map func($E, $V type) type { init func($E, $V type, values meta.EnumFieldStruct(E, ?V, some!(null))) Map(E, V) { map Map(E, V) = undefined match typeinfo!(E) { - .enum |info|: expand for info.fields |field, index| { + .enum |info|: inline for info.fields |field, index| { map.present[index] = false if field!(values, field.name) |value| { map.present[index] = true @@ -15261,7 +15312,7 @@ init func($E, $V type, values meta.EnumFieldStruct(E, ?V, some!(null))) Map(E, V get func($E, $V type, map @Map(E, V), key E) ?V { match typeinfo!(E) { - .enum |info|: expand for info.fields |field, index| { + .enum |info|: inline for info.fields |field, index| { if key == field!(E, field.name) { if map.present[index] { return map.values[index] } return null diff --git a/examples/programs/expand/main.bro b/examples/programs/inline/main.bro similarity index 94% rename from examples/programs/expand/main.bro rename to examples/programs/inline/main.bro index 7218922..be2725f 100644 --- a/examples/programs/expand/main.bro +++ b/examples/programs/inline/main.bro @@ -18,7 +18,7 @@ Value :: union(enum) { enum_score func(kind Kind) i32 { result :: match kind { .first: 1 - expand |value|: { + inline |value|: { yield match value { .second: 2 .third: 3 @@ -31,7 +31,7 @@ enum_score func(kind Kind) i32 { equal_value func(a, b Value) bool { if (tag!(a) != tag!(b)) return false result :: match a { - expand |value, tag|: { + inline |value, tag|: { yield match tag { .number: value == field!(b, tagname!(tag)) .pair: { @@ -49,7 +49,7 @@ equal_value func(a, b Value) bool { increment func(value @mut Value) void { match value^ { - expand |@payload, tag|: match tag { + inline |@payload, tag|: match tag { .number: payload^ += 1 .pair: payload.left += 1 .empty: _ = payload diff --git a/examples/programs/tuples/main.bro b/examples/programs/tuples/main.bro index 390212e..1b7b442 100644 --- a/examples/programs/tuples/main.bro +++ b/examples/programs/tuples/main.bro @@ -11,7 +11,7 @@ format func() []u8 { sum func($T type, value T) i32 { total i32 = 0 match typeinfo!(T) { - .record |record|: expand for record.fields |field| { + .record |record|: inline for record.fields |field| { total += i32(field!(value, field.name)) } else: compile_error!("sum requires a record") @@ -22,7 +22,7 @@ sum func($T type, value T) i32 { static_control func($T type, value T) i32 { total i32 = 0 match typeinfo!(T) { - .record |record|: expand for record.fields |field| { + .record |record|: inline for record.fields |field| { { if field.index == 1 { continue @@ -50,7 +50,7 @@ row_value func(row Row) i32 { static_aggregates func() i32 { total i32 = 0 - expand for {Row {value = 2}, Row {value = 40}} |row| { + inline for {Row {value = 2}, Row {value = 40}} |row| { total += row_value(row) } return total diff --git a/std/enums/enums.hon b/std/enums/enums.hon index d6a2624..b4927c1 100644 --- a/std/enums/enums.hon +++ b/std/enums/enums.hon @@ -17,7 +17,7 @@ init func( map EnumMap(E, V) = undefined match typeinfo!(E) { - .enum |info|: expand for info.fields |field, i| { + .enum |info|: inline for info.fields |field, i| { map.present[i] = false if field!(values, field.name) |value| { @@ -34,7 +34,7 @@ init func( get func($E, $V type, map @EnumMap(E, V), key E) ?V { # fixme: linear lookup; implement an enum index/discriminant map for O(1) lookup match typeinfo!(E) { - .enum |info|: expand for info.fields |field, i| { + .enum |info|: inline for info.fields |field, i| { if key == field!(E, field.name) { if (map.present[i]) return map.values[i] return null diff --git a/std/io/io.hon b/std/io/io.hon index 33dc044..d016e7f 100644 --- a/std/io/io.hon +++ b/std/io/io.hon @@ -111,7 +111,7 @@ stderr func(io Io) Writer { } print func(output Writer, $format []u8, $Args type, args Args) void ! WriteError { - expand for parse_format(format.len, format, Args) |token| { + inline for parse_format(format.len, format, Args) |token| { match token.kind { .unused: break .literal: try write_all(output, format[token.start..token.end]) @@ -427,7 +427,7 @@ hide write_default func(output Writer, $T type, value T) void ! WriteError { .pointer: try write_all(output, value) .slice: try write_all(output, value) .enum |enum_info|: { - expand for enum_info.fields |field| { + inline for enum_info.fields |field| { if value == field!(T, field.name) { try write_all(output, ".") try write_all(output, field.name) diff --git a/std/meta/meta.hon b/std/meta/meta.hon index b1e53f1..73fbd48 100644 --- a/std/meta/meta.hon +++ b/std/meta/meta.hon @@ -49,7 +49,7 @@ EnumFieldStruct func($E, $Field type, $default ?Field) type { names [info.fields.len]mut []u8 = undefined field_types [info.fields.len]mut type = undefined defaults [info.fields.len]mut ?Field = undefined - expand for info.fields |field, index| { + inline for info.fields |field, index| { names[index] = field.name field_types[index] = Field defaults[index] = default