diff --git a/src/bootstrap.zig b/src/bootstrap.zig index f4d4416..2e1e043 100644 --- a/src/bootstrap.zig +++ b/src/bootstrap.zig @@ -505,13 +505,13 @@ pub const Value = struct { cast, cast_to, extend: *Value, - integer_max, + integer_max: *Type, int_from_enum, int_from_pointer, pointer_cast, select, trap, - truncate, + truncate: *Value, va_start, va_end, va_copy, @@ -755,6 +755,21 @@ pub const Module = struct { } } + fn parse_hexadecimal(noalias module: *Module) u64 { + var value: u64 = 0; + while (true) { + const ch = module.content[module.offset]; + if (!lib.is_hex_digit(ch)) { + break; + } + + module.offset += 1; + value = lib.parse.accumulate_hexadecimal(value, ch); + } + + return value; + } + fn parse_decimal(noalias module: *Module) u64 { var value: u64 = 0; while (true) { @@ -1351,6 +1366,8 @@ pub const Module = struct { else => .decimal, }; const value: u64 = switch (token_integer_kind) { + .binary => @trap(), + .octal => @trap(), .decimal => switch (next_ch) { 0...9 => module.report_error(), else => b: { @@ -1358,7 +1375,11 @@ pub const Module = struct { break :b 0; }, }, - else => @trap(), + .hexadecimal => b: { + module.offset += 2; + const v = module.parse_hexadecimal(); + break :b v; + }, }; if (module.content[module.offset] == '.') { @@ -1721,26 +1742,53 @@ pub const Module = struct { fn rule_before_value_intrinsic(noalias module: *Module, value_builder: Value.Builder) *Value { const intrinsic = value_builder.token.value_intrinsic; - switch (intrinsic) { - .extend => { + const value = module.values.add(); + value.* = switch (intrinsic) { + .extend => blk: { module.skip_space(); module.expect_character(left_parenthesis); module.skip_space(); const arg_value = module.parse_value(.{}); module.expect_character(right_parenthesis); - const value = module.values.add(); - value.* = .{ + break :blk .{ .bb = .{ .intrinsic = .{ .extend = arg_value, }, }, }; - return value; + }, + .integer_max => blk: { + module.skip_space(); + module.expect_character(left_parenthesis); + module.skip_space(); + const ty = module.parse_type(); + module.expect_character(right_parenthesis); + break :blk .{ + .bb = .{ + .intrinsic = .{ + .integer_max = ty, + }, + }, + }; + }, + .truncate => blk: { + module.skip_space(); + module.expect_character(left_parenthesis); + module.skip_space(); + const v = module.parse_value(.{}); + module.expect_character(right_parenthesis); + break :blk .{ + .bb = .{ + .intrinsic = .{ + .truncate = v, + }, + }, + }; }, else => @trap(), - } - @trap(); + }; + return value; } fn rule_before_integer(noalias module: *Module, value_builder: Value.Builder) *Value { @@ -2720,6 +2768,20 @@ pub const Module = struct { }; break :blk extension_instruction; }, + .integer_max => |max_type| blk: { + const bit_count = max_type.bb.integer.bit_count; + const max_value = if (bit_count == 64) ~@as(u64, 0) else (@as(u64, 1) << @intCast(bit_count - @intFromBool(max_type.bb.integer.signed))) - 1; + const constant_integer = max_type.resolve(module).handle.to_integer().get_constant(max_value, @intFromBool(false)); + break :blk constant_integer.to_value(); + }, + .truncate => |value_to_truncate| blk: { + if (value_to_truncate.llvm == null) { + module.emit_value(function, value_to_truncate); + } + const llvm_value = value_to_truncate.llvm orelse unreachable; + const truncate = module.llvm.builder.create_truncate(llvm_value, value_type.llvm.handle.?); + break :blk truncate; + }, else => @trap(), }, .dereference => |dereferenceable_value| blk: { @@ -2756,8 +2818,10 @@ pub const Module = struct { @trap(); }, false => { - const type_max = (@as(u64, 1) << @intCast(integer.bit_count)) - 1; - if (constant_integer.value > type_max) { + const bit_count = integer.bit_count; + const max_value = if (bit_count == 64) ~@as(u64, 0) else (@as(u64, 1) << @intCast(bit_count - @intFromBool(integer.signed))) - 1; + + if (constant_integer.value > max_value) { module.report_error(); } }, @@ -2811,6 +2875,12 @@ pub const Module = struct { module.report_error(); } }, + .truncate => |value_to_truncate| { + module.analyze_value_type(function, value_to_truncate, .{}); + if (expected_type.get_bit_size() >= value_to_truncate.type.?.get_bit_size()) { + module.report_error(); + } + }, else => @trap(), }, .dereference => |dereferenceable_value| { @@ -2863,6 +2933,16 @@ pub const Module = struct { .right => variable.type, else => variable.storage.?.type.?, }, + .intrinsic => |intrinsic| switch (intrinsic) { + // TODO: typecheck + .integer_max => |integer_max_type| blk: { + if (integer_max_type.bb != .integer) { + module.report_error(); + } + break :blk integer_max_type; + }, + else => @trap(), + }, else => @trap(), }; diff --git a/src/main.zig b/src/main.zig index e7f06df..59d9b1b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -189,5 +189,7 @@ const names = &[_][]const u8{ "extend", "stack_negation", "basic_pointer", + "integer_max", + "integer_hex", // "pointer", };