refactor: remove enum-map lookup wrappers

This commit is contained in:
2026-10-30 11:17:11 +01:00
parent 30a98db379
commit 31a1bf1995
14 changed files with 118 additions and 117 deletions
+3 -1
View File
@@ -241,9 +241,11 @@ AST `NodeId` values are compilation-wide, so declarations in different files can
AST nodes retain a compact 16-byte layout on the bootstrap target: a kind, three 32-bit payload words and one packed flag byte in existing padding. file-local, foreign-callable, variadic and opaque metadata therefore need neither per-node boolean fields nor another allocation. spans and variable-length payloads remain in parallel storage; cloning and replacement copy the flags with the node. AST nodes retain a compact 16-byte layout on the bootstrap target: a kind, three 32-bit payload words and one packed flag byte in existing padding. file-local, foreign-callable, variadic and opaque metadata therefore need neither per-node boolean fields nor another allocation. spans and variable-length payloads remain in parallel storage; cloning and replacement copy the flags with the node.
the AST renderer displays nested blocks, cleanup bodies/captures and compound operators alongside ordinary statements.
identifier interning is compilation-owned: initialize a `strpool.StringPool`, pass it to `lexer.scan` and `sema.resolve` before the diagnostic store, and release it after lowering. scanning interns identifier spellings once per pool; parsing preserves their IDs in compact AST storage, exposed through `ast.name_id`, while retaining source spans for diagnostics. name resolution keys scopes by those IDs and interns builtin names into the same pool, so identifier hashing and equality do not scan spelling bytes. IDs are meaningful only within their originating pool; independent compilations may assign the same numeric ID to different names. interning failures propagate as infrastructure errors rather than producing an invalid identifier ID. IR retains no pool dependency. identifier interning is compilation-owned: initialize a `strpool.StringPool`, pass it to `lexer.scan` and `sema.resolve` before the diagnostic store, and release it after lowering. scanning interns identifier spellings once per pool; parsing preserves their IDs in compact AST storage, exposed through `ast.name_id`, while retaining source spans for diagnostics. name resolution keys scopes by those IDs and interns builtin names into the same pool, so identifier hashing and equality do not scan spelling bytes. IDs are meaningful only within their originating pool; independent compilations may assign the same numeric ID to different names. interning failures propagate as infrastructure errors rather than producing an invalid identifier ID. IR retains no pool dependency.
compiler token/operator mappings, scalar type metadata and backend spellings use compile-time `@std/enummap` tables; state-dependent layout and control-flow dispatch remain ordinary code. `enummap.init_filled(E, V, storage_default, fields)` initializes unused value slots so sparse maps can become owned compile-time constants without changing which keys are present. `enummap.get` still performs runtime linear lookup; static construction is not a constant-time lookup guarantee. compiler token/operator mappings, scalar type metadata and backend spellings use compile-time `@std/enummap` tables directly; state-dependent layout and control-flow dispatch remain ordinary code. IR exports `integer_minima` and `integer_maxima` maps for shared integer bounds, with absent entries for noninteger types. `enummap.init_default(E, V, storage_default, fields)` initializes unused value slots so sparse maps can become owned compile-time constants without changing which keys are present. `enummap.get` still performs runtime linear lookup; static construction is not a constant-time lookup guarantee.
resolver scopes use `@std/hashmap.AutoHashMap(K, V)`, which shares `init`, `put`, `get` and `deinit` with custom `HashMap` and `StringHashMap`. automatic keys support integers, booleans, enums, distinct types, fixed arrays and records recursively; record padding is ignored. slices, floating-point values, pointers, optionals and unions require explicit hashing and equality through `HashMap` (`StringHashMap` supplies content-based byte-string operations). keys and values are stored by value; referenced resources remain caller-owned. the builtin declaration count is inferred, and builtin ID storage derives its fixed stack-array length from that declaration array rather than repeating a count or initializer. resolver scopes use `@std/hashmap.AutoHashMap(K, V)`, which shares `init`, `put`, `get` and `deinit` with custom `HashMap` and `StringHashMap`. automatic keys support integers, booleans, enums, distinct types, fixed arrays and records recursively; record padding is ignored. slices, floating-point values, pointers, optionals and unions require explicit hashing and equality through `HashMap` (`StringHashMap` supplies content-based byte-string operations). keys and values are stored by value; referenced resources remain caller-owned. the builtin declaration count is inferred, and builtin ID storage derives its fixed stack-array length from that declaration array rather than repeating a count or initializer.
+23 -10
View File
@@ -54,7 +54,7 @@ render_function proc(
render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, depth usize) void ! mem.AllocError { render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, depth usize) void ! mem.AllocError {
for 0..ast.block_statement_count(tree, block) |index| { for 0..ast.block_statement_count(tree, block) |index| {
statement :: ast.block_statement(tree, block, index) statement :: ast.block_statement(tree, block, index)
for 0..depth |_| try append_text(renderer, " ") for (0..depth) |_| try append_text(renderer, " ")
match ast.stmt_kind(tree, statement) { match ast.stmt_kind(tree, statement) {
.declaration: try render_statement(renderer, tree, statement, "") .declaration: try render_statement(renderer, tree, statement, "")
.expression: { .expression: {
@@ -65,6 +65,22 @@ render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, dept
} }
.break_stmt: try append_text(renderer, "break\n") .break_stmt: try append_text(renderer, "break\n")
.continue_stmt: try append_text(renderer, "continue\n") .continue_stmt: try append_text(renderer, "continue\n")
.block_stmt: {
try append_text(renderer, "block\n")
try render_block(renderer, tree, ast.statement_block(tree, statement), depth + 1)
}
.defer_stmt, .errdefer_stmt: {
cleanup :: ast.cleanup_stmt(tree, statement)
keyword :: if (ast.stmt_kind(tree, statement) == .errdefer_stmt) "errdefer" else "defer"
try append_text(renderer, keyword)
if (cleanup.capture) |capture| {
try append_text(renderer, " |")
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, capture)))
try append_text(renderer, "|")
}
try append_text(renderer, "\n")
try render_block(renderer, tree, cleanup.body, depth + 1)
}
.return_stmt: { .return_stmt: {
try append_text(renderer, "return") try append_text(renderer, "return")
if (ast.return_stmt(tree, statement).value) |value| { if (ast.return_stmt(tree, statement).value) |value| {
@@ -86,7 +102,7 @@ render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, dept
try append_text(renderer, "\n") try append_text(renderer, "\n")
try render_block(renderer, tree, conditional.then_block, depth + 1) try render_block(renderer, tree, conditional.then_block, depth + 1)
if (conditional.else_block) |alternative| { if (conditional.else_block) |alternative| {
for 0..depth |_| try append_text(renderer, " ") for (0..depth) |_| try append_text(renderer, " ")
try append_text(renderer, "else\n") try append_text(renderer, "else\n")
try render_block(renderer, tree, alternative, depth + 1) try render_block(renderer, tree, alternative, depth + 1)
} }
@@ -99,7 +115,7 @@ render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, dept
if (assignment.compound) { if (assignment.compound) {
binary :: ast.binary_expr(tree, value) binary :: ast.binary_expr(tree, value)
try append_text(renderer, " ") try append_text(renderer, " ")
try append_text(renderer, assignment_operator_text(binary.operator)) try append_text(renderer, enummap.get(&assignment_operator_texts, binary.operator)?)
try append_text(renderer, "= ") try append_text(renderer, "= ")
value = binary.right value = binary.right
} else { } else {
@@ -126,7 +142,7 @@ render_block proc(renderer @mut Renderer, tree @ast.Tree, block ast.NodeId, dept
else try append_text(renderer, "_") else try append_text(renderer, "_")
if (loop.index_capture) { if (loop.index_capture) {
try append_text(renderer, ", ") try append_text(renderer, ", ")
if (loop.index) |index| try append_text(renderer, ast.source_text(tree, ast.node_span(tree, index))) if (loop.index) |index_capture| try append_text(renderer, ast.source_text(tree, ast.node_span(tree, index_capture)))
else try append_text(renderer, "_") else try append_text(renderer, "_")
} }
try append_text(renderer, "|\n") try append_text(renderer, "|\n")
@@ -152,7 +168,8 @@ render_statement proc(
try append_text(renderer, " ") try append_text(renderer, " ")
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, type))) try append_text(renderer, ast.source_text(tree, ast.node_span(tree, type)))
} }
try append_text(renderer, if (statement.mutability == .constant) " :: " else " := ") binding :: if (statement.mutability == .constant) " :: " else " := "
try append_text(renderer, binding)
try append_text(renderer, ast.source_text(tree, ast.node_span(tree, statement.initializer))) try append_text(renderer, ast.source_text(tree, ast.node_span(tree, statement.initializer)))
try append_text(renderer, "\n") try append_text(renderer, "\n")
} }
@@ -163,7 +180,7 @@ append_text proc(renderer @mut Renderer, text []u8) void ! mem.AllocError {
} }
@hide:file @hide:file
assignment_operator_texts :: $enummap.init_filled( assignment_operator_texts :: $enummap.init_default(
ast.BinaryOperator, []u8, "", { ast.BinaryOperator, []u8, "", {
add = "+", add = "+",
subtract = "-", subtract = "-",
@@ -178,7 +195,3 @@ assignment_operator_texts :: $enummap.init_filled(
}, },
) )
@hide:file
assignment_operator_text proc(operator ast.BinaryOperator) []u8 {
return enummap.get(&assignment_operator_texts, operator)?
}
+10 -9
View File
@@ -1,5 +1,6 @@
import "@std/mem" import "@std/mem"
import "@std/arraylist" import "@std/arraylist"
import "@std/enummap"
import "@source/ir" import "@source/ir"
import "@source/diagnostics" import "@source/diagnostics"
@@ -579,7 +580,7 @@ execute proc(
if instruction.type == .float { if instruction.type == .float {
value = ir.Value{ type = .float, data = ir.ValueData{ real = -operand.data.real } } value = ir.Value{ type = .float, data = ir.ValueData{ real = -operand.data.real } }
} else { } else {
if (operand.data.integer == ir.integer_min(instruction.type)) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span) if (operand.data.integer == enummap.get(&ir.integer_minima, instruction.type)?) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = -operand.data.integer } } value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = -operand.data.integer } }
} }
} }
@@ -628,7 +629,7 @@ execute proc(
} else if ir.unsigned_integer(instruction.type) { } else if ir.unsigned_integer(instruction.type) {
result :: checked_unsigned(instruction.op, left.data.unsigned, right.data.unsigned) result :: checked_unsigned(instruction.op, left.data.unsigned, right.data.unsigned)
if result |unsigned| { if result |unsigned| {
if (unsigned > ir.integer_max(instruction.type)) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span) if (unsigned > enummap.get(&ir.integer_maxima, instruction.type)?) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
value = ir.Value{ type = instruction.type, data = ir.ValueData{ unsigned = unsigned } } value = ir.Value{ type = instruction.type, data = ir.ValueData{ unsigned = unsigned } }
} else { } else {
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
@@ -636,7 +637,7 @@ execute proc(
} else { } else {
result :: checked_integer(instruction.op, left.data.integer, right.data.integer) result :: checked_integer(instruction.op, left.data.integer, right.data.integer)
if result |result_integer| { if result |result_integer| {
if (result_integer < ir.integer_min(instruction.type) or result_integer > i64(ir.integer_max(instruction.type))) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span) if (result_integer < enummap.get(&ir.integer_minima, instruction.type)? or result_integer > i64(enummap.get(&ir.integer_maxima, instruction.type)?)) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = result_integer } } value = ir.Value{ type = instruction.type, data = ir.ValueData{ integer = result_integer } }
} else { } else {
return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span) return try runtime_trap(diagnostic_store, .integer_overflow, instruction.span)
@@ -950,7 +951,7 @@ shift_integer proc(op ir.Op, left ir.Value, count u64) ir.Value {
negative :: signed and left.data.integer < 0 negative :: signed and left.data.integer < 0
if (op == .shift_left_saturating) { if (op == .shift_left_saturating) {
if (bits == 0) return left if (bits == 0) return left
limit :: if (negative) 1 + (mask >> 1) else ir.integer_max(left.type) limit :: if (negative) 1 + (mask >> 1) else enummap.get(&ir.integer_maxima, left.type)?
magnitude :: if (negative) 1 + (bits xor mask) else bits magnitude :: if (negative) 1 + (bits xor mask) else bits
if (count >= width) return integer_from_bits(left.type, limit) if (count >= width) return integer_from_bits(left.type, limit)
if (magnitude > (limit >> count)) return integer_from_bits(left.type, limit) if (magnitude > (limit >> count)) return integer_from_bits(left.type, limit)
@@ -1054,28 +1055,28 @@ convert proc(source ir.Value, target ir.Type) ?ir.Value {
if (ir.unsigned_integer(target)) { if (ir.unsigned_integer(target)) {
if (!(real > -1.0 and real < 18446744073709551616.0)) return null if (!(real > -1.0 and real < 18446744073709551616.0)) return null
integer :: u64(real) integer :: u64(real)
if (integer > ir.integer_max(target)) return null if (integer > enummap.get(&ir.integer_maxima, target)?) return null
result.data = ir.ValueData{ unsigned = integer } result.data = ir.ValueData{ unsigned = integer }
} else { } else {
if (!(real >= -9223372036854775808.0 and real < 9223372036854775808.0)) return null if (!(real >= -9223372036854775808.0 and real < 9223372036854775808.0)) return null
integer :: i64(real) integer :: i64(real)
if (integer < ir.integer_min(target) or integer > i64(ir.integer_max(target))) return null if (integer < enummap.get(&ir.integer_minima, target)? or integer > i64(enummap.get(&ir.integer_maxima, target)?)) return null
result.data = ir.ValueData{ integer = integer } result.data = ir.ValueData{ integer = integer }
} }
return result return result
} }
if (ir.unsigned_integer(source.type)) { if (ir.unsigned_integer(source.type)) {
integer :: source.data.unsigned integer :: source.data.unsigned
if (integer > ir.integer_max(target)) return null if (integer > enummap.get(&ir.integer_maxima, target)?) return null
if (ir.unsigned_integer(target)) result.data = ir.ValueData{ unsigned = integer } if (ir.unsigned_integer(target)) result.data = ir.ValueData{ unsigned = integer }
else result.data = ir.ValueData{ integer = i64(integer) } else result.data = ir.ValueData{ integer = i64(integer) }
} else { } else {
integer :: source.data.integer integer :: source.data.integer
if (ir.unsigned_integer(target)) { if (ir.unsigned_integer(target)) {
if (integer < 0 or u64(integer) > ir.integer_max(target)) return null if (integer < 0 or u64(integer) > enummap.get(&ir.integer_maxima, target)?) return null
result.data = ir.ValueData{ unsigned = u64(integer) } result.data = ir.ValueData{ unsigned = u64(integer) }
} else { } else {
if (integer < ir.integer_min(target) or integer > i64(ir.integer_max(target))) return null if (integer < enummap.get(&ir.integer_minima, target)? or integer > i64(enummap.get(&ir.integer_maxima, target)?)) return null
result.data = ir.ValueData{ integer = integer } result.data = ir.ValueData{ integer = integer }
} }
} }
+7 -15
View File
@@ -35,7 +35,7 @@ aggregate proc(type Type) bool {
} }
@hide:file @hide:file
integer_widths :: $enummap.init_filled(Type, usize, usize(0), { integer_widths :: $enummap.init_default(Type, usize, usize(0), {
i8 = 8, u8 = 8, i8 = 8, u8 = 8,
i16 = 16, u16 = 16, i16 = 16, u16 = 16,
i32 = 32, u32 = 32, i32 = 32, u32 = 32,
@@ -52,8 +52,8 @@ unsigned_integer proc(type Type) bool {
return type == .u8 or type == .u16 or type == .u32 or type == .u64 or type == .usize return type == .u8 or type == .u16 or type == .u32 or type == .u64 or type == .usize
} }
@hide:file #! maxima for supported integer storage types; noninteger keys are absent.
integer_maxima :: $enummap.init_filled(Type, u64, u64(0), { integer_maxima :: $enummap.init_default(Type, u64, u64(0), {
i8 = 127, i8 = 127,
i16 = 32767, i16 = 32767,
i32 = 2147483647, i32 = 2147483647,
@@ -64,12 +64,8 @@ integer_maxima :: $enummap.init_filled(Type, u64, u64(0), {
u64 = maxval!(u64), usize = maxval!(u64), u64 = maxval!(u64), usize = maxval!(u64),
}) })
integer_max proc(type Type) u64 { #! minima for supported integer storage types; noninteger keys are absent.
return enummap.get(&integer_maxima, type)? integer_minima :: $enummap.init_default(Type, i64, i64(0), {
}
@hide:file
integer_minima :: $enummap.init_filled(Type, i64, i64(0), {
i8 = i64(-128), i8 = i64(-128),
i16 = i64(-32768), i16 = i64(-32768),
i32 = i64(-2147483648), i32 = i64(-2147483648),
@@ -77,10 +73,6 @@ integer_minima :: $enummap.init_filled(Type, i64, i64(0), {
u8 = 0, u16 = 0, u32 = 0, u64 = 0, usize = 0, u8 = 0, u16 = 0, u32 = 0, u64 = 0, usize = 0,
}) })
integer_min proc(type Type) i64 {
return enummap.get(&integer_minima, type)?
}
ValueData :: union { ValueData :: union {
integer i64 integer i64
# source pointers use run-wide handles; internal addresses use frame-local IDs below. # source pointers use run-wide handles; internal addresses use frame-local IDs below.
@@ -421,12 +413,12 @@ aligned_size proc(size, alignment usize) usize {
} }
@hide:file @hide:file
scalar_alignments :: $enummap.init_filled(Type, usize, usize(1), { scalar_alignments :: $enummap.init_default(Type, usize, usize(1), {
float = 8, string = 8, function = 8, pointer = 8, float = 8, string = 8, function = 8, pointer = 8,
}) })
@hide:file @hide:file
scalar_sizes :: $enummap.init_filled(Type, usize, usize(0), { scalar_sizes :: $enummap.init_default(Type, usize, usize(0), {
float = 8, function = 8, pointer = 8, float = 8, function = 8, pointer = 8,
string = 16, string = 16,
bool = 1, bool = 1,
+11 -11
View File
@@ -4,14 +4,14 @@ import "@source/ir"
import "@source/diagnostics" import "@source/diagnostics"
@hide:file @hide:file
bitwise_opcodes :: $enummap.init_filled(ir.Op, []u8, "", { bitwise_opcodes :: $enummap.init_default(ir.Op, []u8, "", {
bit_and = "and", bit_and = "and",
bit_or = "or", bit_or = "or",
bit_xor = "xor", bit_xor = "xor",
}) })
@hide:file @hide:file
float_opcodes :: $enummap.init_filled(ir.Op, []u8, "", { float_opcodes :: $enummap.init_default(ir.Op, []u8, "", {
add = "fadd", add = "fadd",
subtract = "fsub", subtract = "fsub",
multiply = "fmul", multiply = "fmul",
@@ -19,14 +19,14 @@ float_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
}) })
@hide:file @hide:file
integer_opcodes :: $enummap.init_filled(ir.Op, []u8, "", { integer_opcodes :: $enummap.init_default(ir.Op, []u8, "", {
add = "add", add = "add",
subtract = "sub", subtract = "sub",
multiply = "mul", multiply = "mul",
}) })
@hide:file @hide:file
float_predicates :: $enummap.init_filled(ir.Op, []u8, "", { float_predicates :: $enummap.init_default(ir.Op, []u8, "", {
equal = "oeq", equal = "oeq",
not_equal = "une", not_equal = "une",
less = "olt", less = "olt",
@@ -36,7 +36,7 @@ float_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
}) })
@hide:file @hide:file
integer_predicates :: $enummap.init_filled(ir.Op, []u8, "", { integer_predicates :: $enummap.init_default(ir.Op, []u8, "", {
equal = "eq", equal = "eq",
not_equal = "ne", not_equal = "ne",
less = "lt", less = "lt",
@@ -46,7 +46,7 @@ integer_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
}) })
@hide:file @hide:file
conversion_upper_bounds :: $enummap.init_filled(ir.Type, []u8, "", { conversion_upper_bounds :: $enummap.init_default(ir.Type, []u8, "", {
i8 = "1.280000e+02", i8 = "1.280000e+02",
i16 = "3.276800e+04", i16 = "3.276800e+04",
i32 = "2.147483648e+09", i32 = "2.147483648e+09",
@@ -387,7 +387,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
minimum :: fresh(state) minimum :: fresh(state)
negative_one :: fresh(state) negative_one :: fresh(state)
overflow :: fresh(state) overflow :: fresh(state)
try io.print(" %r{} = icmp eq i{} %r{}, {}\n", output, {minimum, bits, left, ir.integer_min(instruction.type)}) try io.print(" %r{} = icmp eq i{} %r{}, {}\n", output, {minimum, bits, left, enummap.get(&ir.integer_minima, instruction.type)?})
try io.print(" %r{} = icmp eq i{} %r{}, -1\n", output, {negative_one, bits, right}) try io.print(" %r{} = icmp eq i{} %r{}, -1\n", output, {negative_one, bits, right})
try io.print(" %r{} = and i1 %r{}, %r{}\n", output, {overflow, minimum, negative_one}) try io.print(" %r{} = and i1 %r{}, %r{}\n", output, {overflow, minimum, negative_one})
try check_failure(state, overflow, .integer_overflow, instruction.span) try check_failure(state, overflow, .integer_overflow, instruction.span)
@@ -472,9 +472,9 @@ emit_shift proc(state @mut State, instruction ir.Instruction) usize ! io.WriteEr
if (signed) { if (signed) {
negative :: fresh(state) negative :: fresh(state)
try io.print(" %r{} = icmp slt i{} %r{}, 0\n", output, {negative, bits, left}) try io.print(" %r{} = icmp slt i{} %r{}, 0\n", output, {negative, bits, left})
try io.print(" %r{} = select i1 %r{}, i{} {}, i{} {}\n", output, {limit, negative, bits, ir.integer_min(instruction.type), bits, ir.integer_max(instruction.type)}) try io.print(" %r{} = select i1 %r{}, i{} {}, i{} {}\n", output, {limit, negative, bits, enummap.get(&ir.integer_minima, instruction.type)?, bits, enummap.get(&ir.integer_maxima, instruction.type)?})
} else { } else {
try io.print(" %r{} = or i{} 0, {}\n", output, {limit, bits, ir.integer_max(instruction.type)}) try io.print(" %r{} = or i{} 0, {}\n", output, {limit, bits, enummap.get(&ir.integer_maxima, instruction.type)?})
} }
result :: fresh(state) result :: fresh(state)
try io.print(" %r{} = select i1 %r{}, i{} %r{}, i{} %r{}\n", output, {result, saturate, bits, limit, bits, shifted}) try io.print(" %r{} = select i1 %r{}, i{} %r{}, i{} %r{}\n", output, {result, saturate, bits, limit, bits, shifted})
@@ -684,13 +684,13 @@ emit_conversion proc(state @mut State, instruction ir.Instruction) usize ! io.Wr
} }
if (!source_unsigned and (destination_unsigned or destination_bits < source_bits)) { if (!source_unsigned and (destination_unsigned or destination_bits < source_bits)) {
failed :: fresh(state) failed :: fresh(state)
try io.print(" %r{} = icmp slt i{} %r{}, {}\n", output, {failed, source_bits, operand, ir.integer_min(destination)}) try io.print(" %r{} = icmp slt i{} %r{}, {}\n", output, {failed, source_bits, operand, enummap.get(&ir.integer_minima, destination)?})
try check_failure(state, failed, .integer_overflow, instruction.span) try check_failure(state, failed, .integer_overflow, instruction.span)
} }
if (destination_bits < source_bits or (source_unsigned and !destination_unsigned and destination_bits == source_bits)) { if (destination_bits < source_bits or (source_unsigned and !destination_unsigned and destination_bits == source_bits)) {
failed :: fresh(state) failed :: fresh(state)
predicate []u8 :: if (source_unsigned) "ugt" else "sgt" predicate []u8 :: if (source_unsigned) "ugt" else "sgt"
try io.print(" %r{} = icmp {s} i{} %r{}, {}\n", output, {failed, predicate, source_bits, operand, ir.integer_max(destination)}) try io.print(" %r{} = icmp {s} i{} %r{}, {}\n", output, {failed, predicate, source_bits, operand, enummap.get(&ir.integer_maxima, destination)?})
try check_failure(state, failed, .integer_overflow, instruction.span) try check_failure(state, failed, .integer_overflow, instruction.span)
} }
if (source_bits == destination_bits) return operand if (source_bits == destination_bits) return operand
+5 -10
View File
@@ -71,7 +71,7 @@ emit proc(
.invalid_shift_count, .invalid_shift_count,
] ]
for (memory_codes) |code| { for (memory_codes) |code| {
try io.print("@memory_{s} = private constant ", output, {memory_symbol(code)}) try io.print("@memory_{s} = private constant ", output, {enummap.get(&memory_symbols, code)?})
try bytes_constant(output, enummap.get(diagnostics.Code, []u8, &diagnostics.messages, code)?, false) try bytes_constant(output, enummap.get(diagnostics.Code, []u8, &diagnostics.messages, code)?, false)
try io.write_all(output, "\n") try io.write_all(output, "\n")
} }
@@ -212,7 +212,7 @@ write_type proc(output io.Writer, module @ir.Module, type Type) void ! io.WriteE
} }
@hide:file @hide:file
abi_extensions :: $enummap.init_filled(ir.Type, []u8, "", { abi_extensions :: $enummap.init_default(ir.Type, []u8, "", {
i8 = "signext", i8 = "signext",
i16 = "signext", i16 = "signext",
u8 = "zeroext", u8 = "zeroext",
@@ -502,7 +502,7 @@ check_local proc(state @State, slot u32, read bool, span diagnostics.Span) void
} }
@hide:file @hide:file
memory_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", { memory_symbols :: $enummap.init_default(diagnostics.Code, []u8, "", {
null_unwrap = "null_unwrap", null_unwrap = "null_unwrap",
invalid_slice_bounds = "invalid_slice_bounds", invalid_slice_bounds = "invalid_slice_bounds",
sentinel_mismatch = "sentinel_mismatch", sentinel_mismatch = "sentinel_mismatch",
@@ -514,17 +514,12 @@ memory_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", {
}) })
@hide:file @hide:file
trap_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", { trap_symbols :: $enummap.init_default(diagnostics.Code, []u8, "", {
integer_overflow = "overflow", integer_overflow = "overflow",
index_out_of_bounds = "bounds", index_out_of_bounds = "bounds",
inactive_union_field = "inactive_union", inactive_union_field = "inactive_union",
}) })
@hide:file
memory_symbol proc(code diagnostics.Code) []u8 {
return enummap.get(&memory_symbols, code)?
}
@hide:file @hide:file
trap proc(state @State, code diagnostics.Code, span diagnostics.Span) void ! io.WriteError { trap proc(state @State, code diagnostics.Code, span diagnostics.Span) void ! io.WriteError {
position :: location(state.line_starts, span) position :: location(state.line_starts, span)
@@ -533,7 +528,7 @@ trap proc(state @State, code diagnostics.Code, span diagnostics.Span) void ! io.
length :: message.len length :: message.len
try io.print(" call void @trap(i64 -1, i64 {}, i64 {}, i64 {}, ptr @", state.output, {usize(span.source), position.line, position.column}) try io.print(" call void @trap(i64 -1, i64 {}, i64 {}, i64 {}, ptr @", state.output, {usize(span.source), position.line, position.column})
if (symbol) |name| try io.write_all(state.output, name) if (symbol) |name| try io.write_all(state.output, name)
else try io.print("memory_{s}", state.output, {memory_symbol(code)}) else try io.print("memory_{s}", state.output, {enummap.get(&memory_symbols, code)?})
try io.print(", i64 {})\n unreachable\n", state.output, {length}) try io.print(", i64 {})\n unreachable\n", state.output, {length})
} }
+11 -16
View File
@@ -183,7 +183,7 @@ lower_module proc(
} }
@hide:file @hide:file
base_types :: $enummap.init_filled( base_types :: $enummap.init_default(
typecheck.TypeKind, ir.Type, ir.Type.invalid, { typecheck.TypeKind, ir.Type, ir.Type.invalid, {
int = .int, int = .int,
usize = .usize, usize = .usize,
@@ -957,7 +957,7 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d
array_type = try array_shape(state, pointer.element), span = ast.node_span(tree, id), array_type = try array_shape(state, pointer.element), span = ast.node_span(tree, id),
}) })
} else try emit(state, ir.Instruction{ } else try emit(state, ir.Instruction{
op = binary_op(expression.operator), type = type, left = old, right = right, op = enummap.get(&binary_ops, expression.operator)?, type = type, left = old, right = right,
span = ast.node_span(tree, id), span = ast.node_span(tree, id),
}) })
_ = try emit(state, ir.Instruction{ _ = try emit(state, ir.Instruction{
@@ -1056,7 +1056,7 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d
} }
@hide:file @hide:file
binary_ops :: $enummap.init_filled( binary_ops :: $enummap.init_default(
ast.BinaryOperator, ir.Op, ir.Op.constant, { ast.BinaryOperator, ir.Op, ir.Op.constant, {
add = .add, add = .add,
subtract = .subtract, subtract = .subtract,
@@ -1078,7 +1078,7 @@ binary_ops :: $enummap.init_filled(
) )
@hide:file @hide:file
unary_ops :: $enummap.init_filled( unary_ops :: $enummap.init_default(
ast.UnaryOperator, ir.Op, ir.Op.constant, { ast.UnaryOperator, ir.Op, ir.Op.constant, {
negate = .negate, negate = .negate,
logical_not = .logical_not, logical_not = .logical_not,
@@ -1086,11 +1086,6 @@ unary_ops :: $enummap.init_filled(
}, },
) )
@hide:file
binary_op proc(operator ast.BinaryOperator) ir.Op {
return enummap.get(&binary_ops, operator)?
}
@hide:file @hide:file
lower_logical proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError | diagnostics.CapacityError) { lower_logical proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError | diagnostics.CapacityError) {
expression :: ast.binary_expr(state.tree, id) expression :: ast.binary_expr(state.tree, id)
@@ -1892,8 +1887,8 @@ lower_builtin proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError
if (mem.eql(name, "maxval") or mem.eql(name, "minval")) { if (mem.eql(name, "maxval") or mem.eql(name, "minval")) {
type :: lower_type(state, typecheck.type_of(state.checked, id)) type :: lower_type(state, typecheck.type_of(state.checked, id))
value := ir.Value{ type = type } value := ir.Value{ type = type }
if (mem.eql(name, "maxval")) value.data = ir.ValueData{ unsigned = ir.integer_max(type) } if (mem.eql(name, "maxval")) value.data = ir.ValueData{ unsigned = enummap.get(&ir.integer_maxima, type)? }
else value.data = ir.ValueData{ integer = ir.integer_min(type) } else value.data = ir.ValueData{ integer = enummap.get(&ir.integer_minima, type)? }
return try constant(state, value, span) return try constant(state, value, span)
} }
if (mem.eql(name, "divtrunc")) { if (mem.eql(name, "divtrunc")) {
@@ -2264,9 +2259,9 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
} }
if (expression.operator == .negate and ir.integer_bits(type) != 0 and !ir.unsigned_integer(type) and ast.expr_kind(tree, expression.operand) == .literal_int) { if (expression.operator == .negate and ir.integer_bits(type) != 0 and !ir.unsigned_integer(type) and ast.expr_kind(tree, expression.operand) == .literal_int) {
text :: ast.literal_text(tree, expression.operand) text :: ast.literal_text(tree, expression.operand)
magnitude_limit :: ir.integer_max(type) + 1 magnitude_limit :: enummap.get(&ir.integer_maxima, type)? + 1
if (integer_magnitude(text, magnitude_limit)) |magnitude| { if (integer_magnitude(text, magnitude_limit)) |magnitude| {
if (magnitude == magnitude_limit) return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = ir.integer_min(type) } }, span) if (magnitude == magnitude_limit) return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = enummap.get(&ir.integer_minima, type)? } }, span)
} }
} }
operand :: try lower_expression(state, expression.operand) operand :: try lower_expression(state, expression.operand)
@@ -2302,7 +2297,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
array_type = try array_shape(state, pointer.element), span = span, array_type = try array_shape(state, pointer.element), span = span,
}) })
} }
op :: binary_op(expression.operator) op :: enummap.get(&binary_ops, expression.operator)?
return try emit(state, ir.Instruction{ op = op, type = type, left = left, right = right, span = span }) return try emit(state, ir.Instruction{ op = op, type = type, left = left, right = right, span = span })
} }
.call: { .call: {
@@ -2392,9 +2387,9 @@ lower_number proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError
text :: ast.literal_text(state.tree, id) text :: ast.literal_text(state.tree, id)
type :: lower_type(state, typecheck.type_of(state.checked, id)) type :: lower_type(state, typecheck.type_of(state.checked, id))
if (ir.integer_bits(type) != 0 and !ir.unsigned_integer(type)) { if (ir.integer_bits(type) != 0 and !ir.unsigned_integer(type)) {
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = i64(magnitude) } }, span) if (integer_magnitude(text, enummap.get(&ir.integer_maxima, type)?)) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ integer = i64(magnitude) } }, span)
} else if (ir.unsigned_integer(type)) { } else if (ir.unsigned_integer(type)) {
if (integer_magnitude(text, ir.integer_max(type))) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ unsigned = magnitude } }, span) if (integer_magnitude(text, enummap.get(&ir.integer_maxima, type)?)) |magnitude| return try constant(state, ir.Value{ type = type, data = ir.ValueData{ unsigned = magnitude } }, span)
} else { } else {
value :: strconv.parse_float(state.module.allocator, text) catch |err| { value :: strconv.parse_float(state.module.allocator, text) catch |err| {
match err { match err {
+12 -31
View File
@@ -432,7 +432,7 @@ parse_loop_control proc(state @mut State, allow_else bool) ast.NodeId ! ParseErr
@hide:file @hide:file
parse_assignment proc(state @mut State, target ast.NodeId, allow_else bool) ast.NodeId ! ParseError { parse_assignment proc(state @mut State, target ast.NodeId, allow_else bool) ast.NodeId ! ParseError {
operator :: assignment_operator(current(state).kind) operator :: enummap.get(&assignment_operators, current(state).kind)
state.next_token += 1 state.next_token += 1
value := try parse_expr(state) value := try parse_expr(state)
if ( if (
@@ -939,7 +939,7 @@ parse_function_type proc(state @mut State, start ast.Span, invalid bool) ast.Nod
} }
@hide:file @hide:file
type_starters :: $enummap.init_filled(lexer.TokenKind, bool, false, { type_starters :: $enummap.init_default(lexer.TokenKind, bool, false, {
ident = true, open_bracket = true, struct = true, c_struct = true, opaque = true, ident = true, open_bracket = true, struct = true, c_struct = true, opaque = true,
enum = true, union = true, distinct = true, alias = true, match = true, if = true, enum = true, union = true, distinct = true, alias = true, match = true, if = true,
at = true, star = true, question = true, open_paren = true, proc = true, c_func = true, at = true, star = true, question = true, open_paren = true, proc = true, c_func = true,
@@ -951,7 +951,7 @@ starts_type proc(kind lexer.TokenKind) bool {
} }
@hide:file @hide:file
member_names :: $enummap.init_filled(lexer.TokenKind, bool, false, { member_names :: $enummap.init_default(lexer.TokenKind, bool, false, {
ident = true, if = true, else = true, for = true, inline = true, while = true, ident = true, if = true, else = true, for = true, inline = true, while = true,
proc = true, return = true, yield = true, break = true, continue = true, proc = true, return = true, yield = true, break = true, continue = true,
true = true, false = true, and = true, or = true, xor = true, mut = true, true = true, false = true, and = true, or = true, xor = true, mut = true,
@@ -1388,7 +1388,7 @@ parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) ast.NodeId ! Par
skip_operand_newlines(state) skip_operand_newlines(state)
token := current(state) token := current(state)
expression_start :: state.next_token expression_start :: state.next_token
left := if (prefix_binding_power(token.kind)) |right_bp| { left := if (enummap.get(&prefix_binding_powers, token.kind)) |right_bp| {
state.next_token += 1 state.next_token += 1
operand :: try parse_expr_bp(state, right_bp) operand :: try parse_expr_bp(state, right_bp)
operand_span :: ast.builder_span(state.builder, operand) operand_span :: ast.builder_span(state.builder, operand)
@@ -1518,7 +1518,7 @@ parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) ast.NodeId ! Par
continue continue
} }
if (token.kind == .pipe and !state.allow_bit_or) break if (token.kind == .pipe and !state.allow_bit_or) break
if (infix_binding_power(token.kind)) |power| { if (enummap.get(&infix_binding_powers, token.kind)) |power| {
if (power.left < min_bp) break if (power.left < min_bp) break
state.next_token += 1 state.next_token += 1
right :: try parse_expr_bp(state, power.right) right :: try parse_expr_bp(state, power.right)
@@ -1531,7 +1531,7 @@ parse_expr_bp proc(state @mut State, min_bp BindingPowerScalar) ast.NodeId ! Par
end = right_span.end, end = right_span.end,
source = left_span.source, source = left_span.source,
}, },
binary_operator(token.kind), enummap.get(&binary_operators, token.kind)?,
left, left,
right, right,
) )
@@ -1975,7 +1975,7 @@ skip_continuation_newlines proc(state @mut State) void {
and kind != .close_bracket and kind != .open_bracket and kind != .close_bracket and kind != .open_bracket
and kind != .range and kind != .range_inclusive and kind != .range and kind != .range_inclusive
and kind != .pipe and kind != .bang and kind != .catch and kind != .pipe and kind != .bang and kind != .catch
and infix_binding_power(kind) == null and enummap.get(&infix_binding_powers, kind) == null
) state.next_token = start ) state.next_token = start
} }
@@ -2122,19 +2122,14 @@ consume_either proc(state @mut State, kinds []lexer.TokenKind) lexer.Token ! Syn
} }
@hide:file @hide:file
prefix_binding_powers :: $enummap.init_filled( prefix_binding_powers :: $enummap.init_default(
lexer.TokenKind, BindingPowerScalar, BindingPowerScalar(0), { lexer.TokenKind, BindingPowerScalar, BindingPowerScalar(0), {
minus = BindingPowerScalar(50), bang = BindingPowerScalar(50), tilde = BindingPowerScalar(50), minus = BindingPowerScalar(50), bang = BindingPowerScalar(50), tilde = BindingPowerScalar(50),
ampersand = BindingPowerScalar(50), try = BindingPowerScalar(50), ampersand = BindingPowerScalar(50), try = BindingPowerScalar(50),
}) })
@hide:file @hide:file
prefix_binding_power proc(kind lexer.TokenKind) ?BindingPowerScalar { infix_binding_powers :: $enummap.init_default(lexer.TokenKind, BindingPower,
return enummap.get(&prefix_binding_powers, kind)
}
@hide:file
infix_binding_powers :: $enummap.init_filled(lexer.TokenKind, BindingPower,
BindingPower{ left = BindingPowerScalar(0), right = BindingPowerScalar(0) }, BindingPower{ left = BindingPowerScalar(0), right = BindingPowerScalar(0) },
{ {
or = BindingPower{ left = BindingPowerScalar(2), right = BindingPowerScalar(3) }, or = BindingPower{ left = BindingPowerScalar(2), right = BindingPowerScalar(3) },
@@ -2159,12 +2154,7 @@ infix_binding_powers :: $enummap.init_filled(lexer.TokenKind, BindingPower,
) )
@hide:file @hide:file
infix_binding_power proc(kind lexer.TokenKind) ?BindingPower { binary_operators :: $enummap.init_default(
return enummap.get(&infix_binding_powers, kind)
}
@hide:file
binary_operators :: $enummap.init_filled(
lexer.TokenKind, lexer.TokenKind,
ast.BinaryOperator, ast.BinaryOperator,
ast.BinaryOperator.add, { ast.BinaryOperator.add, {
@@ -2189,18 +2179,13 @@ binary_operators :: $enummap.init_filled(
}, },
) )
@hide:file
binary_operator proc(kind lexer.TokenKind) ast.BinaryOperator {
return enummap.get(&binary_operators, kind)?
}
@hide:file @hide:file
is_assignment_operator proc(kind lexer.TokenKind) bool { is_assignment_operator proc(kind lexer.TokenKind) bool {
return kind == .equal or assignment_operator(kind) != null return kind == .equal or enummap.get(&assignment_operators, kind) != null
} }
@hide:file @hide:file
assignment_operators :: $enummap.init_filled(lexer.TokenKind, ast.BinaryOperator, ast.BinaryOperator.add, { assignment_operators :: $enummap.init_default(lexer.TokenKind, ast.BinaryOperator, ast.BinaryOperator.add, {
plus_equal = .add, plus_equal = .add,
minus_equal = .subtract, minus_equal = .subtract,
star_equal = .multiply, star_equal = .multiply,
@@ -2213,7 +2198,3 @@ assignment_operators :: $enummap.init_filled(lexer.TokenKind, ast.BinaryOperator
shift_left_saturating_equal = .shift_left_saturating, shift_left_saturating_equal = .shift_left_saturating,
}) })
@hide:file
assignment_operator proc(kind lexer.TokenKind) ?ast.BinaryOperator {
return enummap.get(&assignment_operators, kind)
}
+27
View File
@@ -6,6 +6,7 @@ import "@source/diagnostics"
import "@source/strpool" import "@source/strpool"
import "@source/lexer" import "@source/lexer"
import "@source/ast" import "@source/ast"
import "@source/ast/renderer"
parses_expression_precedence_through_tree_views test { parses_expression_precedence_through_tree_views test {
strings := strpool.init(mem.c_allocator) strings := strpool.init(mem.c_allocator)
@@ -2375,3 +2376,29 @@ keeps_type_composition_and_capture_pipes_with_bitwise_or test {
try testing.expect(ast.while_stmt(&tree, ast.block_statement(&tree, body, 4)).capture != null) try testing.expect(ast.while_stmt(&tree, ast.block_statement(&tree, body, 4)).capture != null)
try testing.expect(ast.for_stmt(&tree, ast.block_statement(&tree, body, 5)).capture != null) try testing.expect(ast.for_stmt(&tree, ast.block_statement(&tree, body, 5)).capture != null)
} }
renders_compound_updates_in_scoped_statement_bodies test {
strings := strpool.init(mem.c_allocator)
defer strpool.deinit(&strings)
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
source ::
`run proc() void {
` value := 1
` { value += 2 }
` defer { value -= 3 }
` errdefer |err| { value xor= 4 }
` for (0..2) |item, index| value |= 5
`}
scan_state := lexer.init(mem.c_allocator)
defer lexer.deinit(&scan_state)
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
defer ast.deinit(&tree)
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
output := renderer.init(mem.c_allocator)
defer renderer.deinit(&output)
try renderer.render(&output, &tree)
expected :: "package\n function run\n declaration value := 1\n block\n assignment value += 2\n defer\n assignment value -= 3\n errdefer |err|\n assignment value xor= 4\n for 0..2 |item, index|\n assignment value |= 5\n"
try testing.expect(mem.eql(output.bytes.items, expected))
}
+4 -9
View File
@@ -931,7 +931,7 @@ check_annotation proc(state @mut State, id ast.NodeId, allow_void bool) Type ! (
match binding.kind { match binding.kind {
.invalid: type = invalid_type(binding.data.diagnostic) .invalid: type = invalid_type(binding.data.diagnostic)
.builtin: { .builtin: {
type.kind = builtin_kind(binding.data.builtin) type.kind = enummap.get(&builtin_kinds, binding.data.builtin)?
if (binding.data.builtin == .unavailable) if (binding.data.builtin == .unavailable)
type = invalid_type(try diagnostics.add(state.diagnostics, .invalid_operand, ast.node_span(state.tree, id))) type = invalid_type(try diagnostics.add(state.diagnostics, .invalid_operand, ast.node_span(state.tree, id)))
if (type.kind == .anyopaque and state.pointer_depth == 0) { if (type.kind == .anyopaque and state.pointer_depth == 0) {
@@ -1551,17 +1551,12 @@ builtin_kinds :: $enummap.init(sema.BuiltinType, TypeKind, {
unavailable = .none, unavailable = .none,
}) })
@hide:file
builtin_kind proc(type sema.BuiltinType) TypeKind {
return enummap.get(&builtin_kinds, type)?
}
@hide:file @hide:file
conversion_kind proc(state @State, id ast.NodeId) TypeKind { conversion_kind proc(state @State, id ast.NodeId) TypeKind {
callee :: ast.call_expr(state.tree, id).callee callee :: ast.call_expr(state.tree, id).callee
binding :: sema.binding(state.resolution, callee) binding :: sema.binding(state.resolution, callee)
if (binding.kind != .builtin) return .none if (binding.kind != .builtin) return .none
kind :: builtin_kind(binding.data.builtin) kind :: enummap.get(&builtin_kinds, binding.data.builtin)?
return if (numeric_kind(kind)) kind else .none return if (numeric_kind(kind)) kind else .none
} }
@@ -1589,7 +1584,7 @@ bitwise proc(operator ast.BinaryOperator) bool {
} }
@hide:file @hide:file
integer_widths :: $enummap.init_filled( integer_widths :: $enummap.init_default(
TypeKind, usize, usize(0), { TypeKind, usize, usize(0), {
i8 = 8, u8 = 8, i8 = 8, u8 = 8,
i16 = 16, u16 = 16, i16 = 16, u16 = 16,
@@ -2512,7 +2507,7 @@ evaluate_integer proc(state @mut State, id ast.NodeId, allow_local bool) ?Consta
type_binding :: sema.binding(state.resolution, annotation) type_binding :: sema.binding(state.resolution, annotation)
if ( if (
!integer_kind(state.types[usize(annotation)].kind) !integer_kind(state.types[usize(annotation)].kind)
and (type_binding.kind != .builtin or !integer_kind(builtin_kind(type_binding.data.builtin))) and (type_binding.kind != .builtin or !integer_kind(enummap.get(&builtin_kinds, type_binding.data.builtin)?))
) return null ) return null
} }
return evaluate_integer(state, declaration.initializer, allow_local) return evaluate_integer(state, declaration.initializer, allow_local)
+1 -1
View File
@@ -5297,7 +5297,7 @@ replace proc(state @mut State, target, source ast.NodeId) void ! mem.AllocError
} }
@hide:file @hide:file
builtin_identities :: $enummap.init_filled( builtin_identities :: $enummap.init_default(
sema.BuiltinType, sema.BuiltinType,
sema.BuiltinType, sema.BuiltinType,
sema.BuiltinType.type, { sema.BuiltinType.type, {
+1 -1
View File
@@ -21,7 +21,7 @@ init proc(
#! initializes absent value slots without making their keys present. #! initializes absent value slots without making their keys present.
#! use fully initialized storage when a sparse map must be materialized at compile time. #! use fully initialized storage when a sparse map must be materialized at compile time.
init_filled proc( init_default proc(
$E, $V type, $E, $V type,
storage_default V, storage_default V,
values meta.EnumFieldStruct(E, ?V, some!(null)), values meta.EnumFieldStruct(E, ?V, some!(null)),
+1 -1
View File
@@ -26,7 +26,7 @@ handles_sparse_enum_get test {
} }
@hide:file @hide:file
sparse_optional_values :: $init_filled(TestEnum, ?i16, null, { sparse_optional_values :: $init_default(TestEnum, ?i16, null, {
ident = some!(null), ident = some!(null),
int = some!(some!(i16(42))), int = some!(some!(i16(42))),
}) })
+2 -2
View File
@@ -9045,11 +9045,11 @@ def check_typeinfo_packages(temporary, executable):
import "@std/enummap" import "@std/enummap"
Key :: enum(i16) { absent = -3, present_null = 8, present_value = 21 } Key :: enum(i16) { absent = -3, present_null = 8, present_value = 21 }
main proc() i16 { main proc() i16 {
values :: $(enummap.init_filled(Key, ?i16, null, { values :: $(enummap.init_default(Key, ?i16, null, {
present_null = some!(null), present_null = some!(null),
present_value = some!(some!(i16(42))), present_value = some!(some!(i16(42))),
})) }))
empty :: $(enummap.init_filled(Key, i16, i16(99), {})) empty :: $(enummap.init_default(Key, i16, i16(99), {}))
if (enummap.get(&values, .absent) != null or enummap.get(&empty, .absent) != null) return -1 if (enummap.get(&values, .absent) != null or enummap.get(&empty, .absent) != null) return -1
payload :: enummap.get(&values, .present_null) payload :: enummap.get(&values, .present_null)
if (payload == null or payload? != null) return -2 if (payload == null or payload? != null) return -2