aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLoris Cro <kappaloris@gmail.com>2022-06-09 21:20:25 +0200
committerAndrew Kelley <andrew@ziglang.org>2022-07-19 19:10:12 -0700
commitdd4bd55ef6891109f3a462369a3430d11d5db4ee (patch)
tree58e1a95a870307c9f52956568309b557f556cc05 /src
parent45e3b1a23df6f0f0174b277194b5301662d7c256 (diff)
downloadzig-dd4bd55ef6891109f3a462369a3430d11d5db4ee.tar.gz
zig-dd4bd55ef6891109f3a462369a3430d11d5db4ee.zip
autodoc: rework json printing code
We're now using `std.json.writeStream`, which makes our prints correct in terms of escapes and also reduces the amount of json-related code. Unfortunately, we have to mess around with the json stream writer state whenever we end up using `std.json.stringify` for convenience.
Diffstat (limited to 'src')
-rw-r--r--src/Autodoc.zig540
1 files changed, 137 insertions, 403 deletions
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
index cd2c0d8768..7100816f8f 100644
--- a/src/Autodoc.zig
+++ b/src/Autodoc.zig
@@ -178,9 +178,9 @@ pub fn generateZirData(self: *Autodoc) !void {
try self.packages.put(self.arena, self.module.main_pkg, .{
.name = "root",
.main = main_type_index,
- .table = .{ .data = std.StringHashMapUnmanaged(usize){} },
+ .table = std.StringHashMapUnmanaged(usize){},
});
- try self.packages.entries.items(.value)[0].table.data.put(self.arena, "root", 0);
+ try self.packages.entries.items(.value)[0].table.put(self.arena, "root", 0);
}
var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
@@ -208,7 +208,7 @@ pub fn generateZirData(self: *Autodoc) !void {
.rootPkgName = rootName,
.params = .{ .rootName = "root" },
.packages = self.packages.values(),
- .files = .{ .data = self.files },
+ .files = self.files,
.calls = self.calls.items,
.types = self.types.items,
.decls = self.decls.items,
@@ -313,49 +313,7 @@ const DocData = struct {
// non-hardcoded stuff
astNodes: []AstNode,
calls: []Call,
- files: struct {
- // this struct is a temporary hack to support json serialization
- data: std.AutoArrayHashMapUnmanaged(*File, usize),
- pub fn jsonStringify(
- self: @This(),
- opt: std.json.StringifyOptions,
- w: anytype,
- ) !void {
- var idx: usize = 0;
- var it = self.data.iterator();
- try w.writeAll("{\n");
-
- var options = opt;
- if (options.whitespace) |*ws| ws.indent_level += 1;
- while (it.next()) |kv| : (idx += 1) {
- if (options.whitespace) |ws| try ws.outputIndent(w);
- const builtin = @import("builtin");
- if (builtin.target.os.tag == .windows) {
- try w.print("\"", .{});
- for (kv.key_ptr.*.sub_file_path) |c| {
- if (c == '\\') {
- try w.print("\\\\", .{});
- } else {
- try w.print("{c}", .{c});
- }
- }
- try w.print("\"", .{});
- try w.print(": {d}", .{
- kv.value_ptr.*,
- });
- } else {
- try w.print("\"{s}\": {d}", .{
- kv.key_ptr.*.sub_file_path,
- kv.value_ptr.*,
- });
- }
- if (idx != self.data.count() - 1) try w.writeByte(',');
- try w.writeByte('\n');
- }
- if (opt.whitespace) |ws| try ws.outputIndent(w);
- try w.writeAll("}");
- }
- },
+ files: std.AutoArrayHashMapUnmanaged(*File, usize),
types: []Type,
decls: []Decl,
exprs: []Expr,
@@ -366,6 +324,26 @@ const DocData = struct {
ret: Expr,
};
+ pub fn jsonStringify(
+ self: DocData,
+ opts: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
+ const f_name = @tagName(f);
+ try jsw.objectField(f_name);
+ switch (f) {
+ .files => try writeFileTableToJson(self.files, &jsw),
+ else => {
+ try std.json.stringify(@field(self, f_name), opts, w);
+ jsw.state_index -= 1;
+ },
+ }
+ }
+ try jsw.endObject();
+ }
/// All the type "families" as described by `std.builtin.TypeId`
/// plus a couple extra that are unique to our use case.
///
@@ -399,49 +377,28 @@ const DocData = struct {
name: []const u8 = "(root)",
file: usize = 0, // index into `files`
main: usize = 0, // index into `types`
- table: struct {
- // this struct is a temporary hack to support json serialization
- data: std.StringHashMapUnmanaged(usize),
- pub fn jsonStringify(
- self: @This(),
- opt: std.json.StringifyOptions,
- w: anytype,
- ) !void {
- var idx: usize = 0;
- var it = self.data.iterator();
- try w.writeAll("{\n");
-
- var options = opt;
- if (options.whitespace) |*ws| ws.indent_level += 1;
- while (it.next()) |kv| : (idx += 1) {
- if (options.whitespace) |ws| try ws.outputIndent(w);
- const builtin = @import("builtin");
- if (builtin.target.os.tag == .windows) {
- try w.print("\"", .{});
- for (kv.key_ptr.*) |c| {
- if (c == '\\') {
- try w.print("\\\\", .{});
- } else {
- try w.print("{c}", .{c});
- }
- }
- try w.print("\"", .{});
- try w.print(": {d}", .{
- kv.value_ptr.*,
- });
- } else {
- try w.print("\"{s}\": {d}", .{
- kv.key_ptr.*,
- kv.value_ptr.*,
- });
- }
- if (idx != self.data.count() - 1) try w.writeByte(',');
- try w.writeByte('\n');
+ table: std.StringHashMapUnmanaged(usize),
+
+ pub fn jsonStringify(
+ self: DocPackage,
+ opts: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
+ const f_name = @tagName(f);
+ try jsw.objectField(f_name);
+ switch (f) {
+ .table => try writePackageTableToJson(self.table, &jsw),
+ else => {
+ try std.json.stringify(@field(self, f_name), opts, w);
+ jsw.state_index -= 1;
+ },
}
- if (opt.whitespace) |ws| try ws.outputIndent(w);
- try w.writeAll("}");
}
- },
+ try jsw.endObject();
+ }
};
const Decl = struct {
@@ -466,7 +423,7 @@ const DocData = struct {
};
const Type = union(DocTypeKinds) {
- Unanalyzed: void,
+ Unanalyzed: struct {},
Type: struct { name: []const u8 },
Void: struct { name: []const u8 },
Bool: struct { name: []const u8 },
@@ -568,130 +525,29 @@ const DocData = struct {
pub fn jsonStringify(
self: Type,
- opt: std.json.StringifyOptions,
+ opts: std.json.StringifyOptions,
w: anytype,
) !void {
- try w.print(
- \\{{ "kind": {},
- \\
- , .{@enumToInt(std.meta.activeTag(self))});
- var options = opt;
- if (options.whitespace) |*ws| ws.indent_level += 1;
- switch (self) {
- .Array => |v| try printTypeBody(v, options, w),
- .Bool => |v| try printTypeBody(v, options, w),
- .Void => |v| try printTypeBody(v, options, w),
- .ComptimeExpr => |v| try printTypeBody(v, options, w),
- .ComptimeInt => |v| try printTypeBody(v, options, w),
- .ComptimeFloat => |v| try printTypeBody(v, options, w),
- .Null => |v| try printTypeBody(v, options, w),
- .Optional => |v| try printTypeBody(v, options, w),
- .Struct => |v| try printTypeBody(v, options, w),
- .Fn => |v| try printTypeBody(v, options, w),
- .Union => |v| try printTypeBody(v, options, w),
- .ErrorSet => |v| try printTypeBody(v, options, w),
- .ErrorUnion => |v| try printTypeBody(v, options, w),
- .Enum => |v| try printTypeBody(v, options, w),
- .Int => |v| try printTypeBody(v, options, w),
- .Float => |v| try printTypeBody(v, options, w),
- .Type => |v| try printTypeBody(v, options, w),
- .NoReturn => |v| try printTypeBody(v, options, w),
- .EnumLiteral => |v| try printTypeBody(v, options, w),
- .Pointer => |v| {
- if (options.whitespace) |ws| try ws.outputIndent(w);
- try w.print(
- \\"size": {},
- \\
- , .{@enumToInt(v.size)});
- if (options.whitespace) |ws| try ws.outputIndent(w);
- if (v.sentinel) |sentinel| {
- try w.print(
- \\"sentinel":
- , .{});
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try sentinel.jsonStringify(options, w);
- try w.print(",", .{});
- }
- if (v.@"align") |@"align"| {
- try w.print(
- \\"align":
- , .{});
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try @"align".jsonStringify(options, w);
- try w.print(",", .{});
- }
- if (v.address_space) |address_space| {
- try w.print(
- \\"address_space":
- , .{});
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try address_space.jsonStringify(options, w);
- try w.print(",", .{});
- }
- if (v.bit_start) |bit_start| {
- try w.print(
- \\"bit_start":
- , .{});
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try bit_start.jsonStringify(options, w);
- try w.print(",", .{});
- }
- if (v.host_size) |host_size| {
- try w.print(
- \\"host_size":
- , .{});
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try host_size.jsonStringify(options, w);
- try w.print(",", .{});
+ const active_tag = std.meta.activeTag(self);
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ try jsw.objectField("kind");
+ try jsw.emitNumber(@enumToInt(active_tag));
+ inline for (comptime std.meta.fields(Type)) |case| {
+ if (@field(Type, case.name) == active_tag) {
+ const current_value = @field(self, case.name);
+ inline for (comptime std.meta.fields(case.field_type)) |f| {
+ try jsw.objectField(f.name);
+ if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
+ try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
+ } else {
+ try std.json.stringify(@field(current_value, f.name), opts, w);
+ jsw.state_index -= 1;
+ }
}
- if (options.whitespace) |ws| try ws.outputIndent(w);
- try w.print(
- \\"is_allowzero": {},
- \\"is_mutable": {},
- \\"is_volatile": {},
- \\"has_sentinel": {},
- \\"has_align": {},
- \\"has_addrspace": {},
- \\"has_bit_range": {},
- \\"is_ref": {},
- \\
- , .{ v.is_allowzero, v.is_mutable, v.is_volatile, v.has_sentinel, v.has_align, v.has_addrspace, v.has_bit_range, v.is_ref });
- if (options.whitespace) |ws| try ws.outputIndent(w);
- try w.print(
- \\"child":
- , .{});
-
- if (options.whitespace) |*ws| ws.indent_level += 1;
- try v.child.jsonStringify(options, w);
- },
- else => {
- std.debug.print(
- "TODO: add {s} to `DocData.Type.jsonStringify`\n",
- .{@tagName(self)},
- );
- },
- }
- try w.print("}}", .{});
- }
-
- fn printTypeBody(
- body: anytype,
- options: std.json.StringifyOptions,
- w: anytype,
- ) !void {
- const fields = std.meta.fields(@TypeOf(body));
- inline for (fields) |f, idx| {
- if (options.whitespace) |ws| try ws.outputIndent(w);
- try w.print("\"{s}\": ", .{f.name});
- try std.json.stringify(@field(body, f.name), options, w);
- if (idx != fields.len - 1) try w.writeByte(',');
- try w.writeByte('\n');
- }
- if (options.whitespace) |ws| {
- var up = ws;
- up.indent_level -= 1;
- try up.outputIndent(w);
+ }
}
+ try jsw.endObject();
}
};
@@ -700,13 +556,13 @@ const DocData = struct {
/// type definition will hold an index into `self.types`.
pub const Expr = union(enum) {
comptimeExpr: usize, // index in `comptimeExprs`
- void,
- @"unreachable",
- @"null",
- @"undefined",
+ void: struct {},
+ @"unreachable": struct {},
+ @"null": struct {},
+ @"undefined": struct {},
@"struct": []FieldVal,
bool: bool,
- @"anytype",
+ @"anytype": struct {},
type: usize, // index in `types`
this: usize, // index in `types`
declRef: usize, // index in `decls`
@@ -791,184 +647,40 @@ const DocData = struct {
pub fn jsonStringify(
self: Expr,
- options: std.json.StringifyOptions,
+ opt: std.json.StringifyOptions,
w: anytype,
- ) std.os.WriteError!void {
- switch (self) {
- .void, .@"unreachable", .@"anytype", .@"null", .@"undefined" => {
- try w.print(
- \\{{ "{s}":{{}} }}
- , .{@tagName(self)});
- },
- .type, .comptimeExpr, .call, .this, .declRef, .typeOf, .errorUnion, .errorSets, .alignOf => |v| {
- try w.print(
- \\{{ "{s}":{} }}
- , .{ @tagName(self), v });
- },
- .int => |v| {
- const neg = if (v.negated) "-" else "";
- try w.print(
- \\{{ "int": {s}{} }}
- , .{ neg, v.value });
- },
- .int_big => |v| {
- const neg = if (v.negated) "-" else "";
- try w.print(
- \\{{ "int_big": {s}{s} }}
- , .{ neg, v.value });
- },
- .float => |v| {
- try w.print(
- \\{{ "float": {} }}
- , .{v});
- },
- .float128 => |v| {
- try w.print(
- \\{{ "float128": {} }}
- , .{v});
- },
- .bool => |v| {
- try w.print(
- \\{{ "bool":{} }}
- , .{v});
- },
- .sizeOf => |v| {
- try w.print(
- \\{{ "sizeOf":{} }}
- , .{v});
- },
- .bitSizeOf => |v| {
- try w.print(
- \\{{ "bitSizeOf":{} }}
- , .{v});
- },
- .enumToInt => |v| {
- try w.print(
- \\{{ "enumToInt":{} }}
- , .{v});
- },
- .fieldRef => |v| try std.json.stringify(
- struct { fieldRef: FieldRef }{ .fieldRef = v },
- options,
- w,
- ),
- .as => |v| try std.json.stringify(
- struct { as: As }{ .as = v },
- options,
- w,
- ),
- .@"struct" => |v| try std.json.stringify(
- struct { @"struct": []FieldVal }{ .@"struct" = v },
- options,
- w,
- ),
- .refPath => |v| {
- try w.print("{{ \"refPath\": [", .{});
- for (v) |c, i| {
- const comma = if (i == v.len - 1) "]}" else ",\n";
- try c.jsonStringify(options, w);
- try w.print("{s}", .{comma});
- }
- },
- .switchOp => |v| try std.json.stringify(
- struct { switchOp: SwitchOp }{ .switchOp = v },
- options,
- w,
- ),
- .switchIndex => |v| try std.json.stringify(
- struct { switchIndex: usize }{ .switchIndex = v },
- options,
- w,
- ),
- .cmpxchg => |v| try std.json.stringify(
- struct { cmpxchg: Cmpxchg }{ .cmpxchg = v },
- options,
- w,
- ),
- .cmpxchgIndex => |v| try std.json.stringify(
- struct { cmpxchgIndex: usize }{ .cmpxchgIndex = v },
- options,
- w,
- ),
- .binOp => |v| try std.json.stringify(
- struct { binOp: BinOp }{ .binOp = v },
- options,
- w,
- ),
- .binOpIndex => |v| try std.json.stringify(
- struct { binOpIndex: usize }{ .binOpIndex = v },
- options,
- w,
- ),
- .builtin => |v| try std.json.stringify(
- struct { builtin: Builtin }{ .builtin = v },
- options,
- w,
- ),
- .builtinIndex => |v| try std.json.stringify(
- struct { builtinIndex: usize }{ .builtinIndex = v },
- options,
- w,
- ),
- .builtinBin => |v| try std.json.stringify(
- struct { builtinBin: BuiltinBin }{ .builtinBin = v },
- options,
- w,
- ),
- .builtinBinIndex => |v| try std.json.stringify(
- struct { builtinBinIndex: usize }{ .builtinBinIndex = v },
- options,
- w,
- ),
- .slice => |v| try std.json.stringify(
- struct { slice: Slice }{ .slice = v },
- options,
- w,
- ),
- .sliceIndex => |v| try std.json.stringify(
- struct { sliceIndex: usize }{ .sliceIndex = v },
- options,
- w,
- ),
- .typeOf_peer => |v| try std.json.stringify(
- struct { typeOf_peer: []usize }{ .typeOf_peer = v },
- options,
- w,
- ),
- .array => |v| try std.json.stringify(
- struct { @"array": []usize }{ .@"array" = v },
- options,
- w,
- ),
- .compileError => |v| try std.json.stringify(
- struct { compileError: []const u8 }{ .compileError = v },
- options,
- w,
- ),
- .string => |v| try std.json.stringify(
- struct { string: []const u8 }{ .string = v },
- options,
- w,
- ),
- .enumLiteral => |v| try std.json.stringify(
- struct { @"enumLiteral": []const u8 }{ .@"enumLiteral" = v },
- options,
- w,
- ),
-
- // try w.print("{ len: {},\n", .{v.len});
-
- // if (options.whitespace) |ws| try ws.outputIndent(w);
- // try w.print("typeRef: ", .{});
- // try v.typeRef.jsonStringify(options, w);
-
- // try w.print("{{ \"data\": [", .{});
- // for (v.data) |d, i| {
- // const comma = if (i == v.len - 1) "]}" else ",";
- // try w.print("{d}{s}", .{ d, comma });
- // }
+ ) !void {
+ const active_tag = std.meta.activeTag(self);
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ try jsw.objectField(@tagName(active_tag));
+ inline for (comptime std.meta.fields(Expr)) |case| {
+ if (@field(Expr, case.name) == active_tag) {
+ switch (active_tag) {
+ .int => {
+ if (self.int.negated) try w.writeAll("-");
+ try jsw.emitNumber(self.int.value);
+ },
+ .int_big => {
+ //@panic("TODO: json serialization of big ints!");
+ //if (v.negated) try w.writeAll("-");
+ //try jsw.emitNumber(v.value);
+ },
+ else => {
+ try std.json.stringify(@field(self, case.name), opt, w);
+ jsw.state_index -= 1;
+ // TODO: we should not reach into the state of the
+ // json writer, but alas, this is what's
+ // necessary with the current api.
+ // would be nice to have a proper integration
+ // between the json writer and the generic
+ // std.json.stringify implementation
+ },
+ }
+ }
}
+ try jsw.endObject();
}
};
@@ -1043,7 +755,7 @@ fn walkInstruction(
// that belongs to another package through its file path?
// (ie not through its package name).
// We're bailing for now, but maybe we shouldn't?
- _ = try current_package.table.data.getOrPutValue(
+ _ = try current_package.table.getOrPutValue(
self.arena,
path,
self.packages.getIndex(other_package).?,
@@ -1062,9 +774,7 @@ fn walkInstruction(
result.value_ptr.* = .{
.name = path,
.main = main_type_index,
- .table = .{
- .data = std.StringHashMapUnmanaged(usize){},
- },
+ .table = std.StringHashMapUnmanaged(usize){},
};
// TODO: Add this package as a dependency to the current pakcage
@@ -2464,7 +2174,7 @@ fn walkInstruction(
},
.func, .func_inferred => {
const type_slot_index = self.types.items.len;
- try self.types.append(self.arena, .{ .Unanalyzed = {} });
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
const result = self.analyzeFunction(
file,
@@ -2478,7 +2188,7 @@ fn walkInstruction(
},
.func_extended => {
const type_slot_index = self.types.items.len;
- try self.types.append(self.arena, .{ .Unanalyzed = {} });
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
const result = self.analyzeFunctionExtended(
file,
@@ -2546,13 +2256,17 @@ fn walkInstruction(
if (small.has_lib_name) extra_index += 1;
if (small.has_align) extra_index += 1;
- const value: DocData.WalkResult = if (small.has_init) .{ .expr = .{ .void = {} } } else .{ .expr = .{ .void = {} } };
+ const value: DocData.WalkResult = if (small.has_init) .{
+ .expr = .{ .void = .{} },
+ } else .{
+ .expr = .{ .void = .{} },
+ };
return value;
},
.union_decl => {
const type_slot_index = self.types.items.len;
- try self.types.append(self.arena, .{ .Unanalyzed = {} });
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
var scope: Scope = .{
.parent = parent_scope,
@@ -2672,7 +2386,7 @@ fn walkInstruction(
},
.enum_decl => {
const type_slot_index = self.types.items.len;
- try self.types.append(self.arena, .{ .Unanalyzed = {} });
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
var scope: Scope = .{
.parent = parent_scope,
@@ -2817,7 +2531,7 @@ fn walkInstruction(
},
.struct_decl => {
const type_slot_index = self.types.items.len;
- try self.types.append(self.arena, .{ .Unanalyzed = {} });
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
var scope: Scope = .{
.parent = parent_scope,
@@ -3122,7 +2836,7 @@ fn walkDecls(
};
const walk_result = if (is_test) // TODO: decide if tests should show up at all
- DocData.WalkResult{ .expr = .{ .void = {} } }
+ DocData.WalkResult{ .expr = .{ .void = .{} } }
else
try self.walkInstruction(file, scope, value_index, true);
@@ -3545,7 +3259,7 @@ fn analyzeFunctionExtended(
});
param_type_refs.appendAssumeCapacity(
- DocData.Expr{ .@"anytype" = {} },
+ DocData.Expr{ .@"anytype" = .{} },
);
},
.param, .param_comptime => {
@@ -3699,7 +3413,7 @@ fn analyzeFunction(
});
param_type_refs.appendAssumeCapacity(
- DocData.Expr{ .@"anytype" = {} },
+ DocData.Expr{ .@"anytype" = .{} },
);
},
.param, .param_comptime => {
@@ -3961,13 +3675,13 @@ fn walkRef(
.void_value => {
return DocData.WalkResult{
.typeRef = .{ .type = @enumToInt(Ref.void_type) },
- .expr = .{ .void = {} },
+ .expr = .{ .void = .{} },
};
},
.unreachable_value => {
return DocData.WalkResult{
.typeRef = .{ .type = @enumToInt(Ref.noreturn_type) },
- .expr = .{ .@"unreachable" = {} },
+ .expr = .{ .@"unreachable" = .{} },
};
},
.null_value => {
@@ -4063,3 +3777,23 @@ fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResul
});
return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
}
+
+fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {
+ try jsw.beginObject();
+ var it = map.iterator();
+ while (it.next()) |entry| {
+ try jsw.objectField(entry.key_ptr.*.sub_file_path);
+ try jsw.emitNumber(entry.value_ptr.*);
+ }
+ try jsw.endObject();
+}
+
+fn writePackageTableToJson(map: std.StringHashMapUnmanaged(usize), jsw: anytype) !void {
+ try jsw.beginObject();
+ var it = map.iterator();
+ while (it.next()) |entry| {
+ try jsw.objectField(entry.key_ptr.*);
+ try jsw.emitNumber(entry.value_ptr.*);
+ }
+ try jsw.endObject();
+}