refactor: precompute compiler enum mappings
This commit is contained in:
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user