From e789eddb878b46ab8f81c5a92d61de4c7b50d66e Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 9 Nov 2023 22:26:29 +0200 Subject: [PATCH] Value: print with type --- src/Attribute.zig | 28 ++++++++++----------- src/Ir.zig | 13 +++++++++- src/Parser.zig | 63 ++++++++++++++++++++++------------------------- src/Tree.zig | 2 +- src/Value.zig | 12 ++++++--- 5 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/Attribute.zig b/src/Attribute.zig index a896e447..6ebee43a 100644 --- a/src/Attribute.zig +++ b/src/Attribute.zig @@ -192,7 +192,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool { } } -pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, p: *Parser) !?Diagnostics.Message { +pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, p: *Parser) !?Diagnostics.Message { switch (attr) { inline else => |tag| { const arg_fields = std.meta.fields(@field(attributes, @tagName(tag))); @@ -202,12 +202,12 @@ pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Va inline 0...arg_fields.len - 1 => |arg_i| { if (UnwrapOptional(arg_fields[arg_i].type) != Alignment) unreachable; - if (!val.is(.int, p.comp)) return Diagnostics.Message{ .tag = .alignas_unavailable }; - if (val.compare(.lt, Value.zero, p.comp)) { - return Diagnostics.Message{ .tag = .negative_alignment, .extra = .{ .str = try p.valStr(val) } }; + if (!res.val.is(.int, p.comp)) return Diagnostics.Message{ .tag = .alignas_unavailable }; + if (res.val.compare(.lt, Value.zero, p.comp)) { + return Diagnostics.Message{ .tag = .negative_alignment, .extra = .{ .str = try res.str(p) } }; } - const requested = val.toInt(u29, p.comp) orelse { - return Diagnostics.Message{ .tag = .maximum_alignment, .extra = .{ .str = try p.valStr(val) } }; + const requested = res.val.toInt(u29, p.comp) orelse { + return Diagnostics.Message{ .tag = .maximum_alignment, .extra = .{ .str = try res.str(p) } }; }; if (!std.mem.isValidAlign(requested)) return Diagnostics.Message{ .tag = .non_pow2_align }; @@ -225,24 +225,24 @@ fn diagnoseField( comptime field: ZigType.StructField, comptime Wanted: type, arguments: *Arguments, - val: Value, + res: Parser.Result, node: Tree.Node, p: *Parser, ) !?Diagnostics.Message { - if (val.opt_ref == .none) { + if (res.val.opt_ref == .none) { if (Wanted == Identifier and node.tag == .decl_ref_expr) { @field(@field(arguments, decl.name), field.name) = Identifier{ .tok = node.data.decl_ref }; return null; } return invalidArgMsg(Wanted, .expression); } - const key = p.comp.interner.get(val.ref()); + const key = p.comp.interner.get(res.val.ref()); switch (key) { .int => { if (@typeInfo(Wanted) == .Int) { - @field(@field(arguments, decl.name), field.name) = val.toInt(Wanted, p.comp) orelse return .{ + @field(@field(arguments, decl.name), field.name) = res.val.toInt(Wanted, p.comp) orelse return .{ .tag = .attribute_int_out_of_range, - .extra = .{ .str = try p.valStr(val) }, + .extra = .{ .str = try res.str(p) }, }; return null; } @@ -256,7 +256,7 @@ fn diagnoseField( .extra = .{ .str = decl.name }, }; } - @field(@field(arguments, decl.name), field.name) = try p.removeNull(val); + @field(@field(arguments, decl.name), field.name) = try p.removeNull(res.val); return null; } else if (@typeInfo(Wanted) == .Enum and @hasDecl(Wanted, "opts") and Wanted.opts.enum_kind == .string) { const str = bytes[0 .. bytes.len - 1]; @@ -300,7 +300,7 @@ fn invalidArgMsg(comptime Expected: type, actual: ArgumentType) Diagnostics.Mess }; } -pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, node: Tree.Node, p: *Parser) !?Diagnostics.Message { +pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, node: Tree.Node, p: *Parser) !?Diagnostics.Message { switch (attr) { inline else => |tag| { const decl = @typeInfo(attributes).Struct.decls[@intFromEnum(tag)]; @@ -312,7 +312,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, node const arg_fields = std.meta.fields(@field(attributes, decl.name)); switch (arg_idx) { inline 0...arg_fields.len - 1 => |arg_i| { - return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, val, node, p); + return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, res, node, p); }, else => unreachable, } diff --git a/src/Ir.zig b/src/Ir.zig index 34b6322e..69164228 100644 --- a/src/Ir.zig +++ b/src/Ir.zig @@ -545,7 +545,18 @@ fn writeType(ir: Ir, ty_ref: Interner.Ref, color: bool, w: anytype) !void { fn writeValue(ir: Ir, val_ref: Interner.Ref, color: bool, w: anytype) !void { const v: Value = .{ .opt_ref = @enumFromInt(@intFromEnum(val_ref)) }; if (color) util.setColor(LITERAL, w); - try v.print(ir.interner, w); + const key = ir.interner.get(v.ref()); + switch (key) { + .null => return w.writeAll("nullptr_t"), + .int => |repr| switch (repr) { + inline else => |x| return w.print("{d}", .{x}), + }, + .float => |repr| switch (repr) { + inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}), + }, + .bytes => |b| return std.zig.fmt.stringEscape(b, "", .{}, w), + else => unreachable, // not a value + } } fn writeRef(ir: Ir, ref_map: *RefMap, ref: Ref, color: bool, w: anytype) !void { diff --git a/src/Parser.zig b/src/Parser.zig index dc3440a7..120ef3f1 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -352,7 +352,7 @@ fn expectClosing(p: *Parser, opening: TokenIndex, id: Token.Id) Error!void { } fn errOverflow(p: *Parser, op_tok: TokenIndex, res: Result) !void { - try p.errStr(.overflow, op_tok, try p.valStr(res.val)); + try p.errStr(.overflow, op_tok, try res.str(p)); } fn errExpectedToken(p: *Parser, expected: Token.Id, actual: Token.Id) Error { @@ -414,21 +414,6 @@ pub fn removeNull(p: *Parser, str: Value) !Value { return Value.intern(p.comp, .{ .bytes = p.strings.items[strings_top..] }); } -pub fn valStr(p: *Parser, val: Value) ![]const u8 { - switch (val.opt_ref) { - .none => return "(none)", - .zero => return "0", - .one => return "1", - .null => return "nullptr_t", - else => {}, - } - const strings_top = p.strings.items.len; - defer p.strings.items.len = strings_top; - - try val.print(&p.comp.interner, p.strings.writer()); - return try p.comp.diag.arena.allocator().dupe(u8, p.strings.items[strings_top..]); -} - pub fn typeStr(p: *Parser, ty: Type) ![]const u8 { if (Type.Builder.fromType(ty).str(p.comp.langopts)) |str| return str; const strings_top = p.strings.items.len; @@ -469,9 +454,9 @@ pub fn floatValueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: try w.writeAll(" changes "); if (res.val.isZero(p.comp)) try w.writeAll("non-zero "); try w.writeAll("value from "); - try old_value.print(&p.comp.interner, w); + try old_value.print(res.ty, p.comp, w); try w.writeAll(" to "); - try res.val.print(&p.comp.interner, w); + try res.val.print(int_ty, p.comp, w); return try p.comp.diag.arena.allocator().dupe(u8, p.strings.items[strings_top..]); } @@ -1198,8 +1183,7 @@ fn staticAssertMessage(p: *Parser, cond_node: NodeIndex, message: Result) !?[]co } const bytes = p.comp.interner.get(message.val.ref()).bytes; try buf.ensureUnusedCapacity(bytes.len); - const size: Compilation.CharUnitSize = @enumFromInt(message.ty.elemType().sizeof(p.comp).?); - try Value.printString(bytes, size, buf.writer()); + try Value.printString(bytes, message.ty, p.comp, buf.writer()); } return try p.comp.diag.arena.allocator().dupe(u8, buf.items); } @@ -1612,10 +1596,10 @@ fn attribute(p: *Parser, kind: Attribute.Kind, namespace: ?[]const u8) Error!?Te fn diagnose(p: *Parser, attr: Attribute.Tag, arguments: *Attribute.Arguments, arg_idx: u32, res: Result) !?Diagnostics.Message { if (Attribute.wantsAlignment(attr, arg_idx)) { - return Attribute.diagnoseAlignment(attr, arguments, arg_idx, res.val, p); + return Attribute.diagnoseAlignment(attr, arguments, arg_idx, res, p); } const node = p.nodes.get(@intFromEnum(res.node)); - return Attribute.diagnose(attr, arguments, arg_idx, res.val, node, p); + return Attribute.diagnose(attr, arguments, arg_idx, res, node, p); } /// attributeList : (attribute (',' attribute)*)? @@ -2276,7 +2260,7 @@ fn recordDeclarator(p: *Parser) Error!bool { try p.errTok(.expected_integer_constant_expr, bits_tok); break :bits; } else if (res.val.compare(.lt, Value.zero, p.comp)) { - try p.errStr(.negative_bitwidth, first_tok, try p.valStr(res.val)); + try p.errStr(.negative_bitwidth, first_tok, try res.str(p)); break :bits; } @@ -2736,13 +2720,13 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode { const min_int = (Type{ .specifier = .int }).minInt(p.comp); const min_val = try Value.int(min_int, p.comp); if (e.res.val.compare(.lt, min_val, p.comp)) { - try p.errStr(.enumerator_too_small, name_tok, try p.valStr(e.res.val)); + try p.errStr(.enumerator_too_small, name_tok, try e.res.str(p)); } } else { const max_int = (Type{ .specifier = .int }).maxInt(p.comp); const max_val = try Value.int(max_int, p.comp); if (e.res.val.compare(.gt, max_val, p.comp)) { - try p.errStr(.enumerator_too_large, name_tok, try p.valStr(e.res.val)); + try p.errStr(.enumerator_too_large, name_tok, try e.res.str(p)); } } } @@ -3264,14 +3248,14 @@ fn initializerItem(p: *Parser, il: *InitList, init_ty: Type) Error!bool { try p.errTok(.expected_integer_constant_expr, expr_tok); return error.ParsingFailed; } else if (index_res.val.compare(.lt, Value.zero, p.comp)) { - try p.errStr(.negative_array_designator, l_bracket + 1, try p.valStr(index_res.val)); + try p.errStr(.negative_array_designator, l_bracket + 1, try index_res.str(p)); return error.ParsingFailed; } const max_len = cur_ty.arrayLen() orelse std.math.maxInt(usize); const index_int = index_res.val.toInt(u64, p.comp) orelse std.math.maxInt(u64); if (index_int >= max_len) { - try p.errStr(.oob_array_designator, l_bracket + 1, try p.valStr(index_res.val)); + try p.errStr(.oob_array_designator, l_bracket + 1, try index_res.str(p)); return error.ParsingFailed; } cur_index_hint = cur_index_hint orelse index_int; @@ -4371,7 +4355,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex { const prev = (try some.add(first, last, case + 1)) orelse break :check; // TODO check which value was already handled - try p.errStr(.duplicate_switch_case, case + 1, try p.valStr(first)); + try p.errStr(.duplicate_switch_case, case + 1, try first_item.str(p)); try p.errTok(.previous_case, prev.tok); } else { try p.errStr(.case_not_in_switch, case, "case"); @@ -4811,11 +4795,24 @@ const CallExpr = union(enum) { } }; -const Result = struct { +pub const Result = struct { node: NodeIndex = .none, ty: Type = .{ .specifier = .int }, val: Value = .{}, + pub fn str(res: Result, p: *Parser) ![]const u8 { + switch (res.val.opt_ref) { + .none => return "(none)", + .null => return "nullptr_t", + else => {}, + } + const strings_top = p.strings.items.len; + defer p.strings.items.len = strings_top; + + try res.val.print(res.ty, p.comp, p.strings.writer()); + return try p.comp.diag.arena.allocator().dupe(u8, p.strings.items[strings_top..]); + } + fn expect(res: Result, p: *Parser) Error!void { if (p.in_macro) { if (res.val.opt_ref == .none) { @@ -7327,7 +7324,7 @@ fn checkArrayBounds(p: *Parser, index: Result, array: Result, tok: TokenIndex) ! const record = lhs.getRecord().?; if (data.member.index + 1 == record.fields.len) { if (!index.val.isZero(p.comp)) { - try p.errStr(.old_style_flexible_struct, tok, try p.valStr(index.val)); + try p.errStr(.old_style_flexible_struct, tok, try index.str(p)); } return; } @@ -7337,13 +7334,13 @@ fn checkArrayBounds(p: *Parser, index: Result, array: Result, tok: TokenIndex) ! const index_int = index.val.toInt(u64, p.comp) orelse std.math.maxInt(u64); if (index.ty.isUnsignedInt(p.comp)) { if (index_int >= array_len) { - try p.errStr(.array_after, tok, try p.valStr(index.val)); + try p.errStr(.array_after, tok, try index.str(p)); } } else { if (index.val.compare(.lt, Value.zero, p.comp)) { - try p.errStr(.array_before, tok, try p.valStr(index.val)); + try p.errStr(.array_before, tok, try index.str(p)); } else if (index_int >= array_len) { - try p.errStr(.array_after, tok, try p.valStr(index.val)); + try p.errStr(.array_after, tok, try index.str(p)); } } } diff --git a/src/Tree.zig b/src/Tree.zig index b2757e52..c06d0f2a 100644 --- a/src/Tree.zig +++ b/src/Tree.zig @@ -763,7 +763,7 @@ fn dumpNode(tree: *const Tree, node: NodeIndex, level: u32, mapper: StringIntern if (tree.value_map.get(node)) |val| { if (color) util.setColor(LITERAL, w); try w.writeAll(" (value: "); - try val.print(&tree.comp.interner, w); + try val.print(ty, tree.comp, w); try w.writeByte(')'); } if (tag == .implicit_return and data.return_zero) { diff --git a/src/Value.zig b/src/Value.zig index c24f6a80..9dc01596 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -677,8 +677,11 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons return lhs_bigint.order(rhs_bigint).compare(op); } -pub fn print(v: Value, interner: *const Interner, w: anytype) @TypeOf(w).Error!void { - const key = interner.get(v.ref()); +pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void { + if (ty.is(.bool)) { + return w.writeAll(if (v.isZero(comp)) "false" else "true"); + } + const key = comp.interner.get(v.ref()); switch (key) { .null => return w.writeAll("nullptr_t"), .int => |repr| switch (repr) { @@ -687,12 +690,13 @@ pub fn print(v: Value, interner: *const Interner, w: anytype) @TypeOf(w).Error!v .float => |repr| switch (repr) { inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}), }, - .bytes => |b| return printString(b, .@"1", w), + .bytes => |b| return printString(b, ty, comp, w), else => unreachable, // not a value } } -pub fn printString(bytes: []const u8, size: Compilation.CharUnitSize, w: anytype) @TypeOf(w).Error!void { +pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void { + const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?); const without_null = bytes[0 .. bytes.len - @intFromEnum(size)]; switch (size) { inline .@"1", .@"2" => |sz| {