Skip to content

Commit 28071ac

Browse files
committed
self-hosted translate-c emits a hello world AST
Also breaking std lib API change: the return value of std.zig.parse returns `*ast.Tree` rather than `ast.Tree`. See #1964
1 parent c82acdb commit 28071ac

File tree

9 files changed

+230
-181
lines changed

9 files changed

+230
-181
lines changed

src-self-hosted/compilation.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,9 @@ pub const Compilation = struct {
569569
'i', 'u' => blk: {
570570
for (name[1..]) |byte|
571571
switch (byte) {
572-
'0'...'9' => {},
573-
else => break :blk,
574-
};
572+
'0'...'9' => {},
573+
else => break :blk,
574+
};
575575
const is_signed = name[0] == 'i';
576576
const bit_count = std.fmt.parseUnsigned(u32, name[1..], 10) catch |err| switch (err) {
577577
error.Overflow => return error.Overflow,
@@ -841,11 +841,9 @@ pub const Compilation = struct {
841841
};
842842
errdefer self.gpa().free(source_code);
843843

844-
const tree = try self.gpa().create(ast.Tree);
845-
tree.* = try std.zig.parse(self.gpa(), source_code);
844+
const tree = try std.zig.parse(self.gpa(), source_code);
846845
errdefer {
847846
tree.deinit();
848-
self.gpa().destroy(tree);
849847
}
850848

851849
break :blk try Scope.AstTree.create(self, tree, root_scope);

src-self-hosted/main.zig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -625,15 +625,15 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
625625
const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
626626
defer allocator.free(source_code);
627627

628-
var tree = std.zig.parse(allocator, source_code) catch |err| {
628+
const tree = std.zig.parse(allocator, source_code) catch |err| {
629629
try stderr.print("error parsing stdin: {}\n", err);
630630
os.exit(1);
631631
};
632632
defer tree.deinit();
633633

634634
var error_it = tree.errors.iterator(0);
635635
while (error_it.next()) |parse_error| {
636-
const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
636+
const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>");
637637
defer msg.destroy();
638638

639639
try msg.printToFile(stderr_file, color);
@@ -642,12 +642,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
642642
os.exit(1);
643643
}
644644
if (flags.present("check")) {
645-
const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree);
645+
const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
646646
const code = if (anything_changed) u8(1) else u8(0);
647647
os.exit(code);
648648
}
649649

650-
_ = try std.zig.render(allocator, stdout, &tree);
650+
_ = try std.zig.render(allocator, stdout, tree);
651651
return;
652652
}
653653

@@ -768,7 +768,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
768768
};
769769
defer fmt.loop.allocator.free(source_code);
770770

771-
var tree = std.zig.parse(fmt.loop.allocator, source_code) catch |err| {
771+
const tree = std.zig.parse(fmt.loop.allocator, source_code) catch |err| {
772772
try stderr.print("error parsing file '{}': {}\n", file_path, err);
773773
fmt.any_error = true;
774774
return;
@@ -777,7 +777,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
777777

778778
var error_it = tree.errors.iterator(0);
779779
while (error_it.next()) |parse_error| {
780-
const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, &tree, file_path);
780+
const msg = try errmsg.Msg.createFromParseError(fmt.loop.allocator, parse_error, tree, file_path);
781781
defer fmt.loop.allocator.destroy(msg);
782782

783783
try msg.printToFile(stderr_file, fmt.color);
@@ -788,7 +788,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
788788
}
789789

790790
if (check_mode) {
791-
const anything_changed = try std.zig.render(fmt.loop.allocator, io.null_out_stream, &tree);
791+
const anything_changed = try std.zig.render(fmt.loop.allocator, io.null_out_stream, tree);
792792
if (anything_changed) {
793793
try stderr.print("{}\n", file_path);
794794
fmt.any_error = true;
@@ -798,7 +798,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
798798
const baf = try io.BufferedAtomicFile.create(fmt.loop.allocator, file_path);
799799
defer baf.destroy();
800800

801-
const anything_changed = try std.zig.render(fmt.loop.allocator, baf.stream(), &tree);
801+
const anything_changed = try std.zig.render(fmt.loop.allocator, baf.stream(), tree);
802802
if (anything_changed) {
803803
try stderr.print("{}\n", file_path);
804804
try baf.finish();

src-self-hosted/scope.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ pub const Scope = struct {
163163
pub fn destroy(self: *AstTree, comp: *Compilation) void {
164164
comp.gpa().free(self.tree.source);
165165
self.tree.deinit();
166-
comp.gpa().destroy(self.tree);
167166
comp.gpa().destroy(self);
168167
}
169168

src-self-hosted/stage1.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,10 @@ export fn stage2_translate_c(
8585
resources_path: [*]const u8,
8686
) Error {
8787
var errors: []translate_c.ClangErrMsg = undefined;
88-
out_ast.* = translate_c.translate(args_begin, args_end, switch (mode) {
88+
out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, switch (mode) {
8989
.import => translate_c.Mode.import,
9090
.translate => translate_c.Mode.translate,
9191
}, &errors, resources_path) catch |err| switch (err) {
92-
error.Unimplemented => return Error.Unimplemented,
9392
error.SemanticAnalyzeFail => {
9493
out_errors_ptr.* = errors.ptr;
9594
out_errors_len.* = errors.len;

src-self-hosted/translate_c.zig

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
const std = @import("std");
55
const ast = std.zig.ast;
6+
const Token = std.zig.Token;
67
use @import("clang.zig");
78

89
pub const Mode = enum {
@@ -13,6 +14,7 @@ pub const Mode = enum {
1314
pub const ClangErrMsg = Stage2ErrorMsg;
1415

1516
pub fn translate(
17+
backing_allocator: *std.mem.Allocator,
1618
args_begin: [*]?[*]const u8,
1719
args_end: [*]?[*]const u8,
1820
mode: Mode,
@@ -29,8 +31,49 @@ pub fn translate(
2931
if (errors.len == 0) return error.OutOfMemory;
3032
return error.SemanticAnalyzeFail;
3133
};
34+
defer ZigClangASTUnit_delete(ast_unit);
3235

33-
return error.Unimplemented;
36+
var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
37+
errdefer tree_arena.deinit();
38+
const arena = &tree_arena.allocator;
39+
40+
const root_node = try arena.create(ast.Node.Root);
41+
root_node.* = ast.Node.Root{
42+
.base = ast.Node{ .id = ast.Node.Id.Root },
43+
.decls = ast.Node.Root.DeclList.init(arena),
44+
.doc_comments = null,
45+
// initialized with the eof token at the end
46+
.eof_token = undefined,
47+
};
48+
49+
const tree = try arena.create(ast.Tree);
50+
tree.* = ast.Tree{
51+
.source = undefined, // need to use Buffer.toOwnedSlice later
52+
.root_node = root_node,
53+
.arena_allocator = tree_arena,
54+
.tokens = ast.Tree.TokenList.init(arena),
55+
.errors = ast.Tree.ErrorList.init(arena),
56+
};
57+
58+
var source_buffer = try std.Buffer.initSize(arena, 0);
59+
60+
try appendToken(tree, &source_buffer, "// TODO: implement more than just an empty source file", .LineComment);
61+
62+
try appendToken(tree, &source_buffer, "", .Eof);
63+
tree.source = source_buffer.toOwnedSlice();
64+
return tree;
65+
}
66+
67+
fn appendToken(tree: *ast.Tree, source_buffer: *std.Buffer, src_text: []const u8, token_id: Token.Id) !void {
68+
const start_index = source_buffer.len();
69+
try source_buffer.append(src_text);
70+
const end_index = source_buffer.len();
71+
const new_token = try tree.tokens.addOne();
72+
new_token.* = Token{
73+
.id = token_id,
74+
.start = start_index,
75+
.end = end_index,
76+
};
3477
}
3578

3679
pub fn freeErrors(errors: []ClangErrMsg) void {

std/special/fmt_runner.zig

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,26 +71,26 @@ pub fn main() !void {
7171
const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
7272
defer allocator.free(source_code);
7373

74-
var tree = std.zig.parse(allocator, source_code) catch |err| {
74+
const tree = std.zig.parse(allocator, source_code) catch |err| {
7575
try stderr.print("error parsing stdin: {}\n", err);
7676
os.exit(1);
7777
};
7878
defer tree.deinit();
7979

8080
var error_it = tree.errors.iterator(0);
8181
while (error_it.next()) |parse_error| {
82-
try printErrMsgToFile(allocator, parse_error, &tree, "<stdin>", stderr_file, color);
82+
try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color);
8383
}
8484
if (tree.errors.len != 0) {
8585
os.exit(1);
8686
}
8787
if (flags.present("check")) {
88-
const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree);
88+
const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
8989
const code = if (anything_changed) u8(1) else u8(0);
9090
os.exit(code);
9191
}
9292

93-
_ = try std.zig.render(allocator, stdout, &tree);
93+
_ = try std.zig.render(allocator, stdout, tree);
9494
return;
9595
}
9696

@@ -166,7 +166,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
166166
};
167167
defer fmt.allocator.free(source_code);
168168

169-
var tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
169+
const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
170170
try stderr.print("error parsing file '{}': {}\n", file_path, err);
171171
fmt.any_error = true;
172172
return;
@@ -175,15 +175,15 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
175175

176176
var error_it = tree.errors.iterator(0);
177177
while (error_it.next()) |parse_error| {
178-
try printErrMsgToFile(fmt.allocator, parse_error, &tree, file_path, stderr_file, fmt.color);
178+
try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color);
179179
}
180180
if (tree.errors.len != 0) {
181181
fmt.any_error = true;
182182
return;
183183
}
184184

185185
if (check_mode) {
186-
const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, &tree);
186+
const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree);
187187
if (anything_changed) {
188188
try stderr.print("{}\n", file_path);
189189
fmt.any_error = true;
@@ -193,7 +193,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
193193
const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path);
194194
defer baf.destroy();
195195

196-
const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), &tree);
196+
const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree);
197197
if (anything_changed) {
198198
try stderr.print("{}\n", file_path);
199199
try baf.finish();
@@ -210,9 +210,14 @@ const Fmt = struct {
210210
const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
211211
};
212212

213-
fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, tree: *ast.Tree,
214-
path: []const u8, file: os.File, color: errmsg.Color,) !void
215-
{
213+
fn printErrMsgToFile(
214+
allocator: *mem.Allocator,
215+
parse_error: *const ast.Error,
216+
tree: *ast.Tree,
217+
path: []const u8,
218+
file: os.File,
219+
color: errmsg.Color,
220+
) !void {
216221
const color_on = switch (color) {
217222
errmsg.Color.Auto => file.isTty(),
218223
errmsg.Color.On => true,

std/zig/ast.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ pub const Tree = struct {
1818
pub const ErrorList = SegmentedList(Error, 0);
1919

2020
pub fn deinit(self: *Tree) void {
21-
self.arena_allocator.deinit();
21+
// Here we copy the arena allocator into stack memory, because
22+
// otherwise it would destroy itself while it was still working.
23+
var arena_allocator = self.arena_allocator;
24+
arena_allocator.deinit();
25+
// self is destroyed
2226
}
2327

2428
pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void {

0 commit comments

Comments
 (0)