Skip to content

Commit

Permalink
Cleans up diff with master, resovles some feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
MasonRemaley committed Dec 22, 2024
1 parent 54269df commit b84b65f
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 383 deletions.
2 changes: 1 addition & 1 deletion lib/std/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ test parseInt {
}

/// Like `parseIntWithGenericCharacter`, but with a sign argument.
pub fn parseIntWithSign(
fn parseIntWithSign(
comptime Result: type,
comptime Character: type,
buf: []const Character,
Expand Down
3 changes: 1 addition & 2 deletions lib/std/zig/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
/// Reference to externally-owned data.
source: [:0]const u8,

mode: Mode,

tokens: TokenList.Slice,
/// The root AST node is assumed to be index 0. Since there can be no
/// references to the root node, this means 0 is available to indicate null.
nodes: NodeList.Slice,
extra_data: []Node.Index,
mode: Mode,

errors: []const Error,

Expand Down
90 changes: 54 additions & 36 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8780,22 +8780,36 @@ fn numberLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index, source_node:
}
}

fn failWithNumberError(
astgen: *AstGen,
err: std.zig.number_literal.Error,
token: Ast.TokenIndex,
bytes: []const u8,
) InnerError {
const note = err.noteWithSource(bytes);
const notes: []const u32 = if (note) |n| &.{try astgen.errNoteTok(token, "{s}", .{n})} else &.{};
try astgen.appendErrorTokNotesOff(
token,
@as(u32, @intCast(err.offset())),
"{}",
.{err.fmtWithSource(bytes)},
notes,
);
return error.AnalysisFail;
fn failWithNumberError(astgen: *AstGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) InnerError {
const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null;
switch (err) {
.leading_zero => if (is_float) {
return astgen.failTok(token, "number '{s}' has leading zero", .{bytes});
} else {
return astgen.failTokNotes(token, "number '{s}' has leading zero", .{bytes}, &.{
try astgen.errNoteTok(token, "use '0o' prefix for octal literals", .{}),
});
},
.digit_after_base => return astgen.failTok(token, "expected a digit after base prefix", .{}),
.upper_case_base => |i| return astgen.failOff(token, @intCast(i), "base prefix must be lowercase", .{}),
.invalid_float_base => |i| return astgen.failOff(token, @intCast(i), "invalid base for float literal", .{}),
.repeated_underscore => |i| return astgen.failOff(token, @intCast(i), "repeated digit separator", .{}),
.invalid_underscore_after_special => |i| return astgen.failOff(token, @intCast(i), "expected digit before digit separator", .{}),
.invalid_digit => |info| return astgen.failOff(token, @intCast(info.i), "invalid digit '{c}' for {s} base", .{ bytes[info.i], @tagName(info.base) }),
.invalid_digit_exponent => |i| return astgen.failOff(token, @intCast(i), "invalid digit '{c}' in exponent", .{bytes[i]}),
.duplicate_exponent => |i| return astgen.failOff(token, @intCast(i), "duplicate exponent", .{}),
.exponent_after_underscore => |i| return astgen.failOff(token, @intCast(i), "expected digit before exponent", .{}),
.special_after_underscore => |i| return astgen.failOff(token, @intCast(i), "expected digit before '{c}'", .{bytes[i]}),
.trailing_special => |i| return astgen.failOff(token, @intCast(i), "expected digit after '{c}'", .{bytes[i - 1]}),
.trailing_underscore => |i| return astgen.failOff(token, @intCast(i), "trailing digit separator", .{}),
.duplicate_period => unreachable, // Validated by tokenizer
.invalid_character => 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(i), "sign '{c}' cannot follow digit '{c}' in hex base", .{ bytes[i], bytes[i - 1] });
},
.period_after_exponent => |i| return astgen.failOff(token, @intCast(i), "unexpected period after exponent", .{}),
}
}

fn asmExpr(
Expand Down Expand Up @@ -11384,20 +11398,9 @@ fn parseStrLit(
}
}

fn failWithStrLitError(
astgen: *AstGen,
err: std.zig.string_literal.Error,
token: Ast.TokenIndex,
bytes: []const u8,
offset: u32,
) InnerError {
fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError {
const raw_string = bytes[offset..];
return astgen.failOff(
token,
offset + @as(u32, @intCast(err.offset())),
"{}",
.{err.fmtWithSource(raw_string)},
);
return err.lower(raw_string, offset, AstGen.failOff, .{ astgen, token });
}

fn failNode(
Expand Down Expand Up @@ -11515,7 +11518,7 @@ fn appendErrorTokNotesOff(
comptime format: []const u8,
args: anytype,
notes: []const u32,
) Allocator.Error!void {
) !void {
@branchHint(.cold);
const gpa = astgen.gpa;
const string_bytes = &astgen.string_bytes;
Expand Down Expand Up @@ -11644,17 +11647,32 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice {
}

fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice {
const tree = astgen.tree;
const node_datas = tree.nodes.items(.data);

const start = node_datas[node].lhs;
const end = node_datas[node].rhs;

const gpa = astgen.gpa;
const data = astgen.tree.nodes.items(.data);
const string_bytes = &astgen.string_bytes;
const str_index = string_bytes.items.len;

var parser = std.zig.string_literal.multilineParser(string_bytes.writer(gpa));
var tok_i = data[node].lhs;
while (tok_i <= data[node].rhs) : (tok_i += 1) {
try parser.line(astgen.tree.tokenSlice(tok_i));
// First line: do not append a newline.
var tok_i = start;
{
const slice = tree.tokenSlice(tok_i);
const line_bytes = slice[2..];
try string_bytes.appendSlice(gpa, line_bytes);
tok_i += 1;
}
// Following lines: each line prepends a newline.
while (tok_i <= end) : (tok_i += 1) {
const slice = tree.tokenSlice(tok_i);
const line_bytes = slice[2..];
try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
string_bytes.appendAssumeCapacity('\n');
string_bytes.appendSliceAssumeCapacity(line_bytes);
}

const len = string_bytes.items.len - str_index;
try string_bytes.append(gpa, 0);
return IndexSlice{
Expand Down
70 changes: 0 additions & 70 deletions lib/std/zig/number_literal.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,83 +58,13 @@ pub const Error = union(enum) {
invalid_exponent_sign: usize,
/// Period comes directly after exponent.
period_after_exponent: usize,

pub fn fmtWithSource(self: Error, bytes: []const u8) std.fmt.Formatter(formatErrorWithSource) {
return .{ .data = .{ .err = self, .bytes = bytes } };
}

pub fn noteWithSource(self: Error, bytes: []const u8) ?[]const u8 {
if (self == .leading_zero) {
const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null;
if (!is_float) return "use '0o' prefix for octal literals";
}
return null;
}

pub fn offset(self: Error) usize {
return switch (self) {
.leading_zero => 0,
.digit_after_base => 0,
.upper_case_base => |i| i,
.invalid_float_base => |i| i,
.repeated_underscore => |i| i,
.invalid_underscore_after_special => |i| i,
.invalid_digit => |e| e.i,
.invalid_digit_exponent => |i| i,
.duplicate_period => 0,
.duplicate_exponent => |i| i,
.exponent_after_underscore => |i| i,
.special_after_underscore => |i| i,
.trailing_special => |i| i,
.trailing_underscore => |i| i,
.invalid_character => |i| i,
.invalid_exponent_sign => |i| i,
.period_after_exponent => |i| i,
};
}
};

const FormatWithSource = struct {
bytes: []const u8,
err: Error,
};

fn formatErrorWithSource(
self: FormatWithSource,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = options;
_ = fmt;
switch (self.err) {
.leading_zero => try writer.print("number '{s}' has leading zero", .{self.bytes}),
.digit_after_base => try writer.writeAll("expected a digit after base prefix"),
.upper_case_base => try writer.writeAll("base prefix must be lowercase"),
.invalid_float_base => try writer.writeAll("invalid base for float literal"),
.repeated_underscore => try writer.writeAll("repeated digit separator"),
.invalid_underscore_after_special => try writer.writeAll("expected digit before digit separator"),
.invalid_digit => |info| try writer.print("invalid digit '{c}' for {s} base", .{ self.bytes[info.i], @tagName(info.base) }),
.invalid_digit_exponent => |i| try writer.print("invalid digit '{c}' in exponent", .{self.bytes[i]}),
.duplicate_exponent => try writer.writeAll("duplicate exponent"),
.exponent_after_underscore => try writer.writeAll("expected digit before exponent"),
.special_after_underscore => |i| try writer.print("expected digit before '{c}'", .{self.bytes[i]}),
.trailing_special => |i| try writer.print("expected digit after '{c}'", .{self.bytes[i - 1]}),
.trailing_underscore => try writer.writeAll("trailing digit separator"),
.duplicate_period => try writer.writeAll("duplicate period"),
.invalid_character => try writer.writeAll("invalid character"),
.invalid_exponent_sign => |i| {
const hex = self.bytes.len >= 2 and self.bytes[0] == '0' and self.bytes[1] == 'x';
if (hex) {
try writer.print("sign '{c}' cannot follow digit '{c}' in hex base", .{ self.bytes[i], self.bytes[i - 1] });
} else {
try writer.print("sign '{c}' cannot follow digit '{c}' in current base", .{ self.bytes[i], self.bytes[i - 1] });
}
},
.period_after_exponent => try writer.writeAll("unexpected period after exponent"),
}
}

/// Parse Zig number literal accepted by fmt.parseInt, fmt.parseFloat and big_int.setString.
/// Valid for any input.
pub fn parseNumberLiteral(bytes: []const u8) Result {
Expand Down
Loading

0 comments on commit b84b65f

Please sign in to comment.