refactor: precompute compiler enum mappings

This commit is contained in:
2026-10-30 10:10:43 +01:00
parent d7e637dc3b
commit 30a98db379
13 changed files with 452 additions and 279 deletions
+18 -13
View File
@@ -1,5 +1,6 @@
import "@std/mem"
import "@std/arraylist"
import "@std/enummap"
import "@source/ast"
#! owns output bytes and retains its allocator; release with deinit.
@@ -161,19 +162,23 @@ append_text proc(renderer @mut Renderer, text []u8) void ! mem.AllocError {
for (text) |byte| try arraylist.append(&renderer.bytes, byte)
}
@hide:file
assignment_operator_texts :: $enummap.init_filled(
ast.BinaryOperator, []u8, "", {
add = "+",
subtract = "-",
multiply = "*",
divide = "/",
bit_and = "&",
bit_or = "|",
bit_xor = "xor",
shift_left = "<<",
shift_right = ">>",
shift_left_saturating = "<<|",
},
)
@hide:file
assignment_operator_text proc(operator ast.BinaryOperator) []u8 {
return match operator {
.add: "+"
.subtract: "-"
.multiply: "*"
.divide: "/"
.bit_and: "&"
.bit_or: "|"
.bit_xor: "xor"
.shift_left: "<<"
.shift_right: ">>"
.shift_left_saturating: "<<|"
else: unreachable
}
return enummap.get(&assignment_operator_texts, operator)?
}
+50 -34
View File
@@ -1,6 +1,7 @@
import "@std/mem"
import "@std/arraylist"
import "@std/debug"
import "@std/enummap"
import "@source/diagnostics"
FunctionId :: distinct u32
@@ -33,44 +34,51 @@ aggregate proc(type Type) bool {
return type == .array or type == .record
}
@hide:file
integer_widths :: $enummap.init_filled(Type, usize, usize(0), {
i8 = 8, u8 = 8,
i16 = 16, u16 = 16,
i32 = 32, u32 = 32,
int = 64, isize = 64, usize = 64, u64 = 64,
})
#! integer storage widths for the supported 64-bit target; zero for noninteger types.
integer_bits proc(type Type) usize {
return match type {
.i8, .u8: 8
.i16, .u16: 16
.i32, .u32: 32
.int, .isize, .usize, .u64: 64
else: 0
}
if (enummap.get(&integer_widths, type)) |width| return width
return 0
}
unsigned_integer proc(type Type) bool {
return type == .u8 or type == .u16 or type == .u32 or type == .u64 or type == .usize
}
@hide:file
integer_maxima :: $enummap.init_filled(Type, u64, u64(0), {
i8 = 127,
i16 = 32767,
i32 = 2147483647,
int = u64(maxval!(i64)), isize = u64(maxval!(i64)),
u8 = 255,
u16 = 65535,
u32 = 4294967295,
u64 = maxval!(u64), usize = maxval!(u64),
})
integer_max proc(type Type) u64 {
return match type {
.i8: 127
.i16: 32767
.i32: 2147483647
.int, .isize: u64(maxval!(i64))
.u8: 255
.u16: 65535
.u32: 4294967295
.u64, .usize: maxval!(u64)
else: unreachable
}
return enummap.get(&integer_maxima, type)?
}
@hide:file
integer_minima :: $enummap.init_filled(Type, i64, i64(0), {
i8 = i64(-128),
i16 = i64(-32768),
i32 = i64(-2147483648),
int = minval!(i64), isize = minval!(i64),
u8 = 0, u16 = 0, u32 = 0, u64 = 0, usize = 0,
})
integer_min proc(type Type) i64 {
return match type {
.i8: -128
.i16: -32768
.i32: -2147483648
.int, .isize: minval!(i64)
.u8, .u16, .u32, .u64, .usize: 0
else: unreachable
}
return enummap.get(&integer_minima, type)?
}
ValueData :: union {
@@ -412,24 +420,32 @@ aligned_size proc(size, alignment usize) usize {
return divtrunc!(size + alignment - 1, alignment) * alignment
}
@hide:file
scalar_alignments :: $enummap.init_filled(Type, usize, usize(1), {
float = 8, string = 8, function = 8, pointer = 8,
})
@hide:file
scalar_sizes :: $enummap.init_filled(Type, usize, usize(0), {
float = 8, function = 8, pointer = 8,
string = 16,
bool = 1,
void = 0,
})
storage_alignment proc(module @Module, type Type, shape ArrayId) usize {
if (aggregate(type)) return module.arrays.items[usize(shape)].alignment
bits :: integer_bits(type)
if (bits != 0) return divtrunc!(bits, 8)
return if (type == .float or type == .string or type == .function or type == .pointer) 8 else 1
if (enummap.get(&scalar_alignments, type)) |alignment| return alignment
return 1
}
storage_size proc(module @Module, type Type, shape ArrayId) usize {
if (aggregate(type)) return module.arrays.items[usize(shape)].byte_size
bits :: integer_bits(type)
if (bits != 0) return divtrunc!(bits, 8)
return match type {
.float, .function, .pointer: 8
.string: 16
.bool: 1
.void: 0
else: unreachable
}
return enummap.get(&scalar_sizes, type)?
}
#! loads a scalar or borrows an aggregate from byte cells without allocating.
+8 -4
View File
@@ -1,6 +1,7 @@
import "@std/mem"
import "@std/strmap"
import "@std/arraylist"
import "@std/enummap"
import "@source/diagnostics"
import "@source/strpool"
@@ -474,12 +475,15 @@ is_digit proc(char u8) bool {
}
}
@hide:file
diagnostic_codes :: $enummap.init(ErrorCode, diagnostics.Code, {
float_must_end_with_digit = .float_must_end_with_digit,
unterminated_string = .unterminated_string,
})
@hide:file
diagnostic_code proc(code ErrorCode) diagnostics.Code {
return match code {
.float_must_end_with_digit: .float_must_end_with_digit
.unterminated_string: .unterminated_string
}
return enummap.get(&diagnostic_codes, code)?
}
@hide:file
+63 -48
View File
@@ -1,7 +1,64 @@
import "@std/io"
import "@std/enummap"
import "@source/ir"
import "@source/diagnostics"
@hide:file
bitwise_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
bit_and = "and",
bit_or = "or",
bit_xor = "xor",
})
@hide:file
float_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
add = "fadd",
subtract = "fsub",
multiply = "fmul",
divide = "fdiv",
})
@hide:file
integer_opcodes :: $enummap.init_filled(ir.Op, []u8, "", {
add = "add",
subtract = "sub",
multiply = "mul",
})
@hide:file
float_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
equal = "oeq",
not_equal = "une",
less = "olt",
less_equal = "ole",
greater = "ogt",
greater_equal = "oge",
})
@hide:file
integer_predicates :: $enummap.init_filled(ir.Op, []u8, "", {
equal = "eq",
not_equal = "ne",
less = "lt",
less_equal = "le",
greater = "gt",
greater_equal = "ge",
})
@hide:file
conversion_upper_bounds :: $enummap.init_filled(ir.Type, []u8, "", {
i8 = "1.280000e+02",
i16 = "3.276800e+04",
i32 = "2.147483648e+09",
int = "9.223372036854775808e+18",
isize = "9.223372036854775808e+18",
u8 = "2.560000e+02",
u16 = "6.553600e+04",
u32 = "4.294967296e+09",
u64 = "1.8446744073709551616e+19",
usize = "1.8446744073709551616e+19",
})
@hide
emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruction) void ! io.WriteError {
output :: state.output
@@ -311,12 +368,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
.bit_and, .bit_or, .bit_xor: {
left :: try load(state, instruction.left)
right :: try load(state, instruction.right)
opcode []u8 :: match instruction.op {
.bit_and: "and"
.bit_or: "or"
.bit_xor: "xor"
else: unreachable
}
opcode :: enummap.get(&bitwise_opcodes, instruction.op)?
try io.print(" %r{} = {s} i{} %r{}, %r{}\n", output, {result, opcode, ir.integer_bits(instruction.type), left, right})
}
.shift_left, .shift_right, .shift_left_saturating: result = try emit_shift(state, instruction)
@@ -324,13 +376,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
left :: try load(state, instruction.left)
right :: try load(state, instruction.right)
if (instruction.type == .float) {
opcode []u8 :: match instruction.op {
.add: "fadd"
.subtract: "fsub"
.multiply: "fmul"
.divide: "fdiv"
else: unreachable
}
opcode :: enummap.get(&float_opcodes, instruction.op)?
try io.print(" %r{} = {s} double %r{}, %r{}\n", output, {result, opcode, left, right})
} else if (instruction.op == .divide) {
bits :: ir.integer_bits(instruction.type)
@@ -349,12 +395,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
opcode []u8 :: if (ir.unsigned_integer(instruction.type)) "udiv" else "sdiv"
try io.print(" %r{} = {s} i{} %r{}, %r{}\n", output, {result, opcode, bits, left, right})
} else {
opcode []u8 :: match instruction.op {
.add: "add"
.subtract: "sub"
.multiply: "mul"
else: unreachable
}
opcode :: enummap.get(&integer_opcodes, instruction.op)?
bits :: ir.integer_bits(instruction.type)
sign []u8 :: if (ir.unsigned_integer(instruction.type)) "u" else "s"
pair :: fresh(state)
@@ -370,15 +411,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
right :: try load(state, instruction.right)
operand_type :: state.values[usize(instruction.left)]
if (operand_type.kind == .float) {
predicate []u8 :: match instruction.op {
.equal: "oeq"
.not_equal: "une"
.less: "olt"
.less_equal: "ole"
.greater: "ogt"
.greater_equal: "oge"
else: unreachable
}
predicate :: enummap.get(&float_predicates, instruction.op)?
try io.print(" %r{} = fcmp {s} double %r{}, %r{}\n", output, {result, predicate, left, right})
} else {
prefix []u8 := ""
@@ -386,15 +419,7 @@ emit_instruction proc(state @mut State, block @ir.Block, instruction ir.Instruct
if (ir.unsigned_integer(operand_type.kind)) prefix = "u"
else prefix = "s"
}
predicate []u8 :: match instruction.op {
.equal: "eq"
.not_equal: "ne"
.less: "lt"
.less_equal: "le"
.greater: "gt"
.greater_equal: "ge"
else: unreachable
}
predicate :: enummap.get(&integer_predicates, instruction.op)?
try io.print(" %r{} = icmp {s}{s} ", output, {result, prefix, predicate})
try write_type(output, state.module, operand_type)
try io.print(" %r{}, %r{}\n", output, {left, right})
@@ -644,17 +669,7 @@ emit_conversion proc(state @mut State, instruction ir.Instruction) usize ! io.Wr
upper_valid :: fresh(state)
valid :: fresh(state)
failed :: fresh(state)
upper []u8 :: match destination {
.i8: "1.280000e+02"
.i16: "3.276800e+04"
.i32: "2.147483648e+09"
.int, .isize: "9.223372036854775808e+18"
.u8: "2.560000e+02"
.u16: "6.553600e+04"
.u32: "4.294967296e+09"
.u64, .usize: "1.8446744073709551616e+19"
else: unreachable
}
upper :: enummap.get(&conversion_upper_bounds, destination)?
try io.print(" %r{} = call double @llvm.trunc.f64(double %r{})\n", output, {truncated, operand})
if (destination_unsigned) try io.print(" %r{} = fcmp oge double %r{}, 0.0\n", output, {lower_valid, truncated})
else try io.print(" %r{} = fcmp oge double %r{}, -{s}\n", output, {lower_valid, truncated, upper})
+33 -23
View File
@@ -211,13 +211,19 @@ write_type proc(output io.Writer, module @ir.Module, type Type) void ! io.WriteE
}
}
@hide:file
abi_extensions :: $enummap.init_filled(ir.Type, []u8, "", {
i8 = "signext",
i16 = "signext",
u8 = "zeroext",
u16 = "zeroext",
bool = "zeroext",
})
@hide:file
abi_extension proc(kind ir.Type) []u8 {
return match kind {
.i8, .i16: "signext"
.u8, .u16, .bool: "zeroext"
else: ""
}
if (enummap.get(&abi_extensions, kind)) |extension| return extension
return ""
}
@hide
@@ -495,34 +501,38 @@ check_local proc(state @State, slot u32, read bool, span diagnostics.Span) void
try io.print(" call void @check_init(ptr %i{}, i1 {}, i64 {}, i64 {}, i64 {})\n", state.output, {slot, read, usize(span.source), position.line, position.column})
}
@hide:file
memory_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", {
null_unwrap = "null_unwrap",
invalid_slice_bounds = "invalid_slice_bounds",
sentinel_mismatch = "sentinel_mismatch",
overlapping_memory_copy = "overlapping_memory_copy",
unsupported_foreign_call = "unsupported_foreign_call",
invalid_pointer_access = "invalid_pointer_access",
division_by_zero = "division_by_zero",
invalid_shift_count = "invalid_shift_count",
})
@hide:file
trap_symbols :: $enummap.init_filled(diagnostics.Code, []u8, "", {
integer_overflow = "overflow",
index_out_of_bounds = "bounds",
inactive_union_field = "inactive_union",
})
@hide:file
memory_symbol proc(code diagnostics.Code) []u8 {
return match code {
.null_unwrap: "null_unwrap"
.invalid_slice_bounds: "invalid_slice_bounds"
.sentinel_mismatch: "sentinel_mismatch"
.overlapping_memory_copy: "overlapping_memory_copy"
.unsupported_foreign_call: "unsupported_foreign_call"
.invalid_pointer_access: "invalid_pointer_access"
.division_by_zero: "division_by_zero"
.invalid_shift_count: "invalid_shift_count"
else: unreachable
}
return enummap.get(&memory_symbols, code)?
}
@hide:file
trap proc(state @State, code diagnostics.Code, span diagnostics.Span) void ! io.WriteError {
position :: location(state.line_starts, span)
symbol []u8 :: match code {
.integer_overflow: "overflow"
.index_out_of_bounds: "bounds"
.inactive_union_field: "inactive_union"
else: ""
}
symbol :: enummap.get(&trap_symbols, code)
message :: enummap.get(diagnostics.Code, []u8, &diagnostics.messages, code)?
length :: message.len
try io.print(" call void @trap(i64 -1, i64 {}, i64 {}, i64 {}, ptr @", state.output, {usize(span.source), position.line, position.column})
if (symbol.len != 0) try io.write_all(state.output, symbol)
if (symbol) |name| try io.write_all(state.output, name)
else try io.print("memory_{s}", state.output, {memory_symbol(code)})
try io.print(", i64 {})\n unreachable\n", state.output, {length})
}
+65 -48
View File
@@ -1,6 +1,7 @@
import "@std/mem"
import "@std/arraylist"
import "@std/strconv"
import "@std/enummap"
import "@ffi/c"
import "@source/ast"
import "@source/diagnostics"
@@ -181,35 +182,43 @@ lower_module proc(
return module
}
@hide:file
base_types :: $enummap.init_filled(
typecheck.TypeKind, ir.Type, ir.Type.invalid, {
int = .int,
usize = .usize,
i8 = .i8,
i16 = .i16,
i32 = .i32,
isize = .isize,
u8 = .u8,
u16 = .u16,
u32 = .u32,
u64 = .u64,
array = .array,
record = .record,
pointer = .pointer,
float = .float,
bool = .bool,
string = .string,
void = .void,
function = .function,
none = .invalid,
invalid = .invalid,
range = .invalid,
type_value = .invalid,
null = .invalid,
anyopaque = .invalid,
},
)
@hide:file
lower_type proc(state @State, type typecheck.Type) ir.Type {
if (type.kind == .enumeration) return lower_type(state, typecheck.Type{ kind = typecheck.enum_type(state.checked, type.enum_type).backing })
if (type.kind == .slice) return .record
if (type.kind == .fallible) return .record
if (type.kind == .optional) return lower_optional_type(state, typecheck.array_type(state.checked, type.array_type).element)
return match type.kind {
.int: .int
.usize: .usize
.i8: .i8
.i16: .i16
.i32: .i32
.isize: .isize
.u8: .u8
.u16: .u16
.u32: .u32
.u64: .u64
.array: .array
.record: .record
.pointer: .pointer
.float: .float
.bool: .bool
.string: .string
.void: .void
.function: .function
.enumeration: unreachable
.none, .invalid, .range, .type_value, .null, .anyopaque: .invalid
.slice, .optional, .fallible: unreachable
}
return enummap.get(&base_types, type.kind)?
}
@hide:file
@@ -1046,27 +1055,40 @@ lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | d
}
}
@hide:file
binary_ops :: $enummap.init_filled(
ast.BinaryOperator, ir.Op, ir.Op.constant, {
add = .add,
subtract = .subtract,
multiply = .multiply,
divide = .divide,
bit_and = .bit_and,
bit_or = .bit_or,
bit_xor = .bit_xor,
shift_left = .shift_left,
shift_right = .shift_right,
shift_left_saturating = .shift_left_saturating,
equal = .equal,
not_equal = .not_equal,
less = .less,
less_equal = .less_equal,
greater = .greater,
greater_equal = .greater_equal,
},
)
@hide:file
unary_ops :: $enummap.init_filled(
ast.UnaryOperator, ir.Op, ir.Op.constant, {
negate = .negate,
logical_not = .logical_not,
bit_not = .bit_not,
},
)
@hide:file
binary_op proc(operator ast.BinaryOperator) ir.Op {
return match operator {
.add: .add
.subtract: .subtract
.multiply: .multiply
.divide: .divide
.bit_and: .bit_and
.bit_or: .bit_or
.bit_xor: .bit_xor
.shift_left: .shift_left
.shift_right: .shift_right
.shift_left_saturating: .shift_left_saturating
.equal: .equal
.not_equal: .not_equal
.less: .less
.less_equal: .less_equal
.greater: .greater
.greater_equal: .greater_equal
.logical_and, .logical_or: unreachable
}
return enummap.get(&binary_ops, operator)?
}
@hide:file
@@ -2249,12 +2271,7 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
}
operand :: try lower_expression(state, expression.operand)
if (state.terminated or trap_type(state, id)) return ir.no_value
op ir.Op :: match expression.operator {
.negate: .negate
.logical_not: .logical_not
.bit_not: .bit_not
.address_of, .dereference, .unwrap: unreachable
}
op :: enummap.get(&unary_ops, expression.operator)?
return try emit(state, ir.Instruction{ op = op, type = type, left = operand, span = span })
}
.binary: {
+97 -61
View File
@@ -1,5 +1,6 @@
import "@std/mem"
import "@std/arraylist"
import "@std/enummap"
import "@source/diagnostics"
import "@source/lexer"
@@ -937,24 +938,32 @@ parse_function_type proc(state @mut State, start ast.Span, invalid bool) ast.Nod
return id
}
@hide:file
type_starters :: $enummap.init_filled(lexer.TokenKind, bool, false, {
ident = true, open_bracket = true, struct = true, c_struct = true, opaque = 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,
})
@hide:file
starts_type proc(kind lexer.TokenKind) bool {
return (
kind == .ident or kind == .open_bracket or kind == .struct or kind == .c_struct or kind == .opaque
or kind == .enum or kind == .union or kind == .distinct or kind == .alias or kind == .match
or kind == .if
or kind == .at or kind == .star or kind == .question or kind == .open_paren or kind == .proc or kind == .c_func
)
return enummap.get(&type_starters, kind) != null
}
@hide:file
member_names :: $enummap.init_filled(lexer.TokenKind, bool, false, {
ident = true, if = true, else = true, for = true, inline = true, while = true,
proc = true, return = true, yield = true, break = true, continue = true,
true = true, false = true, and = true, or = true, xor = true, mut = true,
struct = true, c_struct = true, opaque = true, enum = true, union = true,
distinct = true, alias = true, match = true, import = true, test = true,
c_func = true, null = true, undefined = true, try = true, catch = true,
defer = true, errdefer = true,
})
@hide:file
member_name proc(kind lexer.TokenKind) bool {
return match kind {
.ident, .if, .else, .for, .inline, .while, .proc, .return, .yield, .break, .continue,
.true, .false, .and, .or, .xor, .mut, .struct, .c_struct, .opaque, .enum, .union, .distinct,
.alias, .match, .import, .test, .c_func, .null, .undefined, .try, .catch, .defer, .errdefer: true
else: false
}
return enummap.get(&member_names, kind) != null
}
@hide:file
@@ -2112,52 +2121,77 @@ consume_either proc(state @mut State, kinds []lexer.TokenKind) lexer.Token ! Syn
return .unexpected_token
}
@hide:file
prefix_binding_powers :: $enummap.init_filled(
lexer.TokenKind, BindingPowerScalar, BindingPowerScalar(0), {
minus = BindingPowerScalar(50), bang = BindingPowerScalar(50), tilde = BindingPowerScalar(50),
ampersand = BindingPowerScalar(50), try = BindingPowerScalar(50),
})
@hide:file
prefix_binding_power proc(kind lexer.TokenKind) ?BindingPowerScalar {
return match kind {
.minus, .bang, .tilde, .ampersand, .try: BindingPowerScalar(50)
else: null
}
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) },
{
or = BindingPower{ left = BindingPowerScalar(2), right = BindingPowerScalar(3) },
and = BindingPower{ left = BindingPowerScalar(4), right = BindingPowerScalar(5) },
equal_equal = BindingPower{ left = BindingPowerScalar(10), right = BindingPowerScalar(11) },
not_equal = BindingPower{ left = BindingPowerScalar(10), right = BindingPowerScalar(11) },
less = BindingPower{ left = BindingPowerScalar(20), right = BindingPowerScalar(21) },
less_equal = BindingPower{ left = BindingPowerScalar(20), right = BindingPowerScalar(21) },
greater = BindingPower{ left = BindingPowerScalar(20), right = BindingPowerScalar(21) },
greater_equal = BindingPower{ left = BindingPowerScalar(20), right = BindingPowerScalar(21) },
ampersand = BindingPower{ left = BindingPowerScalar(22), right = BindingPowerScalar(23) },
xor = BindingPower{ left = BindingPowerScalar(22), right = BindingPowerScalar(23) },
pipe = BindingPower{ left = BindingPowerScalar(22), right = BindingPowerScalar(23) },
shift_left = BindingPower{ left = BindingPowerScalar(25), right = BindingPowerScalar(26) },
shift_right = BindingPower{ left = BindingPowerScalar(25), right = BindingPowerScalar(26) },
shift_left_saturating = BindingPower{ left = BindingPowerScalar(25), right = BindingPowerScalar(26) },
plus = BindingPower{ left = BindingPowerScalar(30), right = BindingPowerScalar(31) },
minus = BindingPower{ left = BindingPowerScalar(30), right = BindingPowerScalar(31) },
star = BindingPower{ left = BindingPowerScalar(40), right = BindingPowerScalar(41) },
slash = BindingPower{ left = BindingPowerScalar(40), right = BindingPowerScalar(41) },
},
)
@hide:file
infix_binding_power proc(kind lexer.TokenKind) ?BindingPower {
return match kind {
.or: BindingPower{ left = BindingPowerScalar(2), right = BindingPowerScalar(3) }
.and: BindingPower{ left = BindingPowerScalar(4), right = BindingPowerScalar(5) }
.equal_equal, .not_equal: BindingPower{ left = BindingPowerScalar(10), right = BindingPowerScalar(11) }
.less, .less_equal, .greater, .greater_equal: BindingPower{ left = BindingPowerScalar(20), right = BindingPowerScalar(21) }
.ampersand, .xor, .pipe: BindingPower{ left = BindingPowerScalar(22), right = BindingPowerScalar(23) }
.shift_left, .shift_right, .shift_left_saturating: BindingPower{ left = BindingPowerScalar(25), right = BindingPowerScalar(26) }
.plus, .minus: BindingPower{ left = BindingPowerScalar(30), right = BindingPowerScalar(31) }
.star, .slash: BindingPower{ left = BindingPowerScalar(40), right = BindingPowerScalar(41) }
else: null
}
return enummap.get(&infix_binding_powers, kind)
}
@hide:file
binary_operators :: $enummap.init_filled(
lexer.TokenKind,
ast.BinaryOperator,
ast.BinaryOperator.add, {
and = .logical_and,
or = .logical_or,
plus = .add,
minus = .subtract,
star = .multiply,
slash = .divide,
ampersand = .bit_and,
pipe = .bit_or,
xor = .bit_xor,
shift_left = .shift_left,
shift_right = .shift_right,
shift_left_saturating = .shift_left_saturating,
equal_equal = .equal,
not_equal = .not_equal,
less = .less,
less_equal = .less_equal,
greater = .greater,
greater_equal = .greater_equal,
},
)
@hide:file
binary_operator proc(kind lexer.TokenKind) ast.BinaryOperator {
return match kind {
.and: .logical_and
.or: .logical_or
.plus: .add
.minus: .subtract
.star: .multiply
.slash: .divide
.ampersand: .bit_and
.pipe: .bit_or
.xor: .bit_xor
.shift_left: .shift_left
.shift_right: .shift_right
.shift_left_saturating: .shift_left_saturating
.equal_equal: .equal
.not_equal: .not_equal
.less: .less
.less_equal: .less_equal
.greater: .greater
.greater_equal: .greater_equal
else: unreachable
}
return enummap.get(&binary_operators, kind)?
}
@hide:file
@@ -2165,19 +2199,21 @@ is_assignment_operator proc(kind lexer.TokenKind) bool {
return kind == .equal or assignment_operator(kind) != null
}
@hide:file
assignment_operators :: $enummap.init_filled(lexer.TokenKind, ast.BinaryOperator, ast.BinaryOperator.add, {
plus_equal = .add,
minus_equal = .subtract,
star_equal = .multiply,
slash_equal = .divide,
ampersand_equal = .bit_and,
pipe_equal = .bit_or,
xor_equal = .bit_xor,
shift_left_equal = .shift_left,
shift_right_equal = .shift_right,
shift_left_saturating_equal = .shift_left_saturating,
})
@hide:file
assignment_operator proc(kind lexer.TokenKind) ?ast.BinaryOperator {
return match kind {
.plus_equal: .add
.minus_equal: .subtract
.star_equal: .multiply
.slash_equal: .divide
.ampersand_equal: .bit_and
.pipe_equal: .bit_or
.xor_equal: .bit_xor
.shift_left_equal: .shift_left
.shift_right_equal: .shift_right
.shift_left_saturating_equal: .shift_left_saturating
else: null
}
return enummap.get(&assignment_operators, kind)
}
+42 -34
View File
@@ -3,6 +3,7 @@ import "@std/mem"
import "@std/arraylist"
import "@std/hashmap"
import "@std/strconv"
import "@std/enummap"
import "@source/ast"
import "@source/diagnostics"
sema :: import "@source/sema"
@@ -1521,35 +1522,38 @@ numeric_kind proc(kind TypeKind) bool {
return integer_kind(kind) or kind == .float
}
@hide:file
builtin_kinds :: $enummap.init(sema.BuiltinType, TypeKind, {
int = .int, i64 = .int,
float = .float, f64 = .float,
i8 = .i8,
i16 = .i16,
i32 = .i32,
isize = .isize,
u8 = .u8,
u16 = .u16,
u32 = .u32,
u64 = .u64, uint = .u64,
usize = .usize,
bool = .bool,
string = .string,
void = .void,
anyopaque = .anyopaque,
type = .type_value,
c_int = .i32,
c_uint = .u32,
c_long = .int, c_longlong = .int,
c_ulong = .u64, c_ulonglong = .u64,
c_char = .i8,
c_uchar = .u8,
c_short = .i16,
c_ushort = .u16,
unavailable = .none,
})
@hide:file
builtin_kind proc(type sema.BuiltinType) TypeKind {
return match type {
.int, .i64: .int
.float, .f64: .float
.i8: .i8
.i16: .i16
.i32: .i32
.isize: .isize
.u8: .u8
.u16: .u16
.u32: .u32
.u64, .uint: .u64
.usize: .usize
.bool: .bool
.string: .string
.void: .void
.anyopaque: .anyopaque
.type: .type_value
.c_int: .i32
.c_uint: .u32
.c_long, .c_longlong: .int
.c_ulong, .c_ulonglong: .u64
.c_char: .i8
.c_uchar: .u8
.c_short: .i16
.c_ushort: .u16
.unavailable: .none
}
return enummap.get(&builtin_kinds, type)?
}
@hide:file
@@ -1584,15 +1588,19 @@ bitwise proc(operator ast.BinaryOperator) bool {
return operator == .bit_and or operator == .bit_or or operator == .bit_xor or shift(operator)
}
@hide:file
integer_widths :: $enummap.init_filled(
TypeKind, usize, usize(0), {
i8 = 8, u8 = 8,
i16 = 16, u16 = 16,
i32 = 32, u32 = 32,
int = 64, isize = 64, u64 = 64, usize = 64,
})
@hide:file
integer_width proc(kind TypeKind) usize {
return match kind {
.i8, .u8: 8
.i16, .u16: 16
.i32, .u32: 32
.int, .isize, .u64, .usize: 64
else: 0
}
if (enummap.get(&integer_widths, kind)) |width| return width
return 0
}
@hide:file
+19 -12
View File
@@ -1,6 +1,7 @@
import "@std/mem"
import "@std/arraylist"
import "@std/hashmap"
import "@std/enummap"
import "@source/ast"
import "@source/diagnostics"
import "@source/strpool"
@@ -5295,20 +5296,26 @@ replace proc(state @mut State, target, source ast.NodeId) void ! mem.AllocError
ast.replace_node(state.builder, target, source)
}
@hide:file
builtin_identities :: $enummap.init_filled(
sema.BuiltinType,
sema.BuiltinType,
sema.BuiltinType.type, {
i64 = .int, c_long = .int, c_longlong = .int,
f64 = .float,
uint = .u64, c_ulong = .u64, c_ulonglong = .u64,
c_char = .i8,
c_uchar = .u8,
c_short = .i16,
c_ushort = .u16,
c_int = .i32,
c_uint = .u32,
})
@hide:file
builtin_identity proc(kind sema.BuiltinType) sema.BuiltinType {
return match kind {
.i64, .c_long, .c_longlong: .int
.f64: .float
.uint, .c_ulong, .c_ulonglong: .u64
.c_char: .i8
.c_uchar: .u8
.c_short: .i16
.c_ushort: .u16
.c_int: .i32
.c_uint: .u32
else: kind
}
if (enummap.get(&builtin_identities, kind)) |identity| return identity
return kind
}
@hide:file