From e1f5ad3cc875d255946cafc92e0b415a285919c9 Mon Sep 17 00:00:00 2001 From: Dominic <4678790+dweiller@users.noreply.github.com> Date: Sun, 7 May 2023 18:05:53 +1000 Subject: [PATCH] Fix parsing of hexadecimal literals --- lib/std/zig/number_literal.zig | 10 +++------- src/AstGen.zig | 6 ++++-- .../compile_errors/number_literal_bad_exponent.zig | 13 +++++++++++++ 3 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 test/cases/compile_errors/number_literal_bad_exponent.zig diff --git a/lib/std/zig/number_literal.zig b/lib/std/zig/number_literal.zig index 1b41908371..b021190ad9 100644 --- a/lib/std/zig/number_literal.zig +++ b/lib/std/zig/number_literal.zig @@ -44,8 +44,6 @@ pub const Error = union(enum) { duplicate_period, /// Float literal has multiple exponents. duplicate_exponent: usize, - /// Decimal float has hexadecimal exponent. - invalid_hex_exponent: usize, /// Exponent comes directly after '_' digit separator. exponent_after_underscore: usize, /// Special character (+-.) comes directly after exponent. @@ -103,7 +101,6 @@ pub fn parseNumberLiteral(bytes: []const u8) Result { }, 'e', 'E' => if (base == 10) { float = true; - if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } }; if (exponent) return .{ .failure = .{ .duplicate_exponent = i } }; if (underscore) return .{ .failure = .{ .exponent_after_underscore = i } }; special = c; @@ -112,10 +109,8 @@ pub fn parseNumberLiteral(bytes: []const u8) Result { }, 'p', 'P' => if (base == 16) { float = true; - if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } }; if (exponent) return .{ .failure = .{ .duplicate_exponent = i } }; if (underscore) return .{ .failure = .{ .exponent_after_underscore = i } }; - if (base != 16) return .{ .failure = .{ .invalid_hex_exponent = i } }; special = c; exponent = true; continue; @@ -123,7 +118,7 @@ pub fn parseNumberLiteral(bytes: []const u8) Result { '.' => { float = true; if (base != 10 and base != 16) return .{ .failure = .{ .invalid_float_base = 2 } }; - if (period) return .{ .failure = .{ .duplicate_exponent = i } }; + if (period) return .{ .failure = .duplicate_period }; period = true; if (underscore) return .{ .failure = .{ .special_after_underscore = i } }; special = c; @@ -131,7 +126,8 @@ pub fn parseNumberLiteral(bytes: []const u8) Result { }, '+', '-' => { switch (special) { - 'p', 'P', 'e', 'E' => {}, + 'p', 'P' => {}, + 'e', 'E' => if (base != 10) return .{ .failure = .{ .invalid_exponent_sign = i } }, else => return .{ .failure = .{ .invalid_exponent_sign = i } }, } special = c; diff --git a/src/AstGen.zig b/src/AstGen.zig index 749e3d28c4..300aae8d77 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7622,14 +7622,16 @@ fn failWithNumberError(astgen: *AstGen, err: std.zig.number_literal.Error, token .invalid_digit => |info| return astgen.failOff(token, @intCast(u32, info.i), "invalid digit '{c}' for {s} base", .{ bytes[info.i], @tagName(info.base) }), .invalid_digit_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "invalid digit '{c}' in exponent", .{bytes[i]}), .duplicate_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "duplicate exponent", .{}), - .invalid_hex_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "hex exponent in decimal float", .{}), .exponent_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before exponent", .{}), .special_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before '{c}'", .{bytes[i]}), .trailing_special => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit after '{c}'", .{bytes[i - 1]}), .trailing_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "trailing digit separator", .{}), .duplicate_period => unreachable, // Validated by tokenizer .invalid_character => unreachable, // Validated by tokenizer - .invalid_exponent_sign => unreachable, // Validated by tokenizer + .invalid_exponent_sign => |i| { + assert(bytes.len >= 2 and bytes[0] == '0' and bytes[1] == 'x'); // Validated by tokenizer + return astgen.failOff(token, @intCast(u32, i), "sign '{c}' cannot follow digit '{c}' in hex base", .{ bytes[i], bytes[i - 1] }); + }, } } diff --git a/test/cases/compile_errors/number_literal_bad_exponent.zig b/test/cases/compile_errors/number_literal_bad_exponent.zig new file mode 100644 index 0000000000..158c205018 --- /dev/null +++ b/test/cases/compile_errors/number_literal_bad_exponent.zig @@ -0,0 +1,13 @@ +const a = 0x1e-4; +const b = 0x1e+4; +const c = 0x1E-4; +const d = 0x1E+4; + +// error +// backend=stage2 +// target=native +// +// :1:15: error: sign '-' cannot follow digit 'e' in hex base +// :2:15: error: sign '+' cannot follow digit 'e' in hex base +// :3:15: error: sign '-' cannot follow digit 'E' in hex base +// :4:15: error: sign '+' cannot follow digit 'E' in hex base