diff options
| author | Veikka Tuominen <git@vexu.eu> | 2021-01-30 14:56:36 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2021-03-08 00:33:56 +0200 |
| commit | 0a7be71bc2e58a5375ceed0b1b9850bd33717a0b (patch) | |
| tree | 37036778f4688684c92e843e4d5468edc04edd86 /src/codegen/c.zig | |
| parent | cfc19eace71c92ecd7e138db6d961271a1b6c126 (diff) | |
| download | zig-0a7be71bc2e58a5375ceed0b1b9850bd33717a0b.tar.gz zig-0a7be71bc2e58a5375ceed0b1b9850bd33717a0b.zip | |
stage2 cbe: non pointer optionals
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index fe87a5994a..084c653d1c 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -32,6 +32,34 @@ pub const CValue = union(enum) { }; pub const CValueMap = std.AutoHashMap(*Inst, CValue); +pub const TypedefMap = std.HashMap(Type, struct { name: []const u8, rendered: []u8 }, Type.hash, Type.eql, std.hash_map.default_max_load_percentage); + +fn formatTypeAsCIdentifier( + data: Type, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + var buffer = [1]u8{0} ** 128; + // We don't care if it gets cut off, it's still more unique than a number + var buf = std.fmt.bufPrint(&buffer, "{}", .{data}) catch &buffer; + + for (buf) |c, i| { + switch (c) { + 0 => return writer.writeAll(buf[0..i]), + 'a'...'z', 'A'...'Z', '_', '$' => {}, + '0'...'9' => if (i == 0) { + buf[i] = '_'; + }, + else => buf[i] = '_', + } + } + return writer.writeAll(buf); +} + +pub fn typeToCIdentifier(t: Type) std.fmt.Formatter(formatTypeAsCIdentifier) { + return .{ .data = t }; +} /// This data is available when outputting .c code for a Module. /// It is not available when generating .h file. @@ -115,6 +143,7 @@ pub const DeclGen = struct { decl: *Decl, fwd_decl: std.ArrayList(u8), error_msg: ?*Module.ErrorMsg, + typedefs: TypedefMap, fn fail(dg: *DeclGen, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, .{ @@ -325,22 +354,55 @@ pub const DeclGen = struct { const child_type = t.optionalChild(&opt_buf); if (t.isPtrLikeOptional()) { return dg.renderType(w, child_type); + } else if (dg.typedefs.get(t)) |some| { + return w.writeAll(some.name); } - // TODO this needs to be typedeffed since different structs are different types. - try w.writeAll("struct { "); - try dg.renderType(w, child_type); - try w.writeAll(" payload; bool is_null; }"); + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + const bw = buffer.writer(); + + try bw.writeAll("typedef struct { "); + try dg.renderType(bw, child_type); + try bw.writeAll(" payload; bool is_null; } "); + const name_index = buffer.items.len; + try bw.print("zig_opt_{s}_t;\n", .{typeToCIdentifier(child_type)}); + + const rendered = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered); + const name = rendered[name_index .. rendered.len - 2]; + + try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1); + try w.writeAll(name); + dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); }, .ErrorSet => { comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2); try w.writeAll("uint16_t"); }, .ErrorUnion => { - // TODO this needs to be typedeffed since different structs are different types. - try w.writeAll("struct { "); - try dg.renderType(w, t.errorUnionChild()); - try w.writeAll(" payload; uint16_t error; }"); + if (dg.typedefs.get(t)) |some| { + return w.writeAll(some.name); + } + const child_type = t.errorUnionChild(); + + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + const bw = buffer.writer(); + + try bw.writeAll("typedef struct { "); + try dg.renderType(bw, t.errorUnionChild()); + try bw.writeAll(" payload; uint16_t error; } "); + const name_index = buffer.items.len; + try bw.print("zig_err_union_{s}_t;\n", .{typeToCIdentifier(child_type)}); + + const rendered = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered); + const name = rendered[name_index .. rendered.len - 2]; + + try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1); + try w.writeAll(name); + dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); }, .Null, .Undefined => unreachable, // must be const or comptime else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{ |
