stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
// This is the userland implementation of translate-c which will be used by both stage1
|
2019-04-29 21:21:45 -07:00
|
|
|
// and stage2. Currently the only way it is used is with `zig translate-c-2`.
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
|
|
|
|
const std = @import("std");
|
2019-04-21 14:24:58 -07:00
|
|
|
const ast = std.zig.ast;
|
2019-04-26 12:40:29 -07:00
|
|
|
const Token = std.zig.Token;
|
2019-04-21 14:24:58 -07:00
|
|
|
use @import("clang.zig");
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
|
2019-04-21 14:24:58 -07:00
|
|
|
pub const Mode = enum {
|
|
|
|
import,
|
|
|
|
translate,
|
|
|
|
};
|
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
pub const ClangErrMsg = Stage2ErrorMsg;
|
|
|
|
|
2019-04-29 21:21:45 -07:00
|
|
|
pub const Error = error {
|
|
|
|
OutOfMemory,
|
|
|
|
};
|
|
|
|
|
|
|
|
const Context = struct {
|
|
|
|
tree: *ast.Tree,
|
|
|
|
source_buffer: *std.Buffer,
|
|
|
|
err: Error,
|
|
|
|
};
|
|
|
|
|
2019-04-21 16:37:39 -07:00
|
|
|
pub fn translate(
|
2019-04-26 12:40:29 -07:00
|
|
|
backing_allocator: *std.mem.Allocator,
|
2019-04-21 16:37:39 -07:00
|
|
|
args_begin: [*]?[*]const u8,
|
|
|
|
args_end: [*]?[*]const u8,
|
|
|
|
mode: Mode,
|
|
|
|
errors: *[]ClangErrMsg,
|
2019-04-21 16:46:34 -07:00
|
|
|
resources_path: [*]const u8,
|
2019-04-21 16:37:39 -07:00
|
|
|
) !*ast.Tree {
|
2019-04-21 16:46:34 -07:00
|
|
|
const ast_unit = ZigClangLoadFromCommandLine(
|
|
|
|
args_begin,
|
|
|
|
args_end,
|
|
|
|
&errors.ptr,
|
|
|
|
&errors.len,
|
|
|
|
resources_path,
|
|
|
|
) orelse {
|
|
|
|
if (errors.len == 0) return error.OutOfMemory;
|
|
|
|
return error.SemanticAnalyzeFail;
|
|
|
|
};
|
2019-04-26 12:40:29 -07:00
|
|
|
defer ZigClangASTUnit_delete(ast_unit);
|
2019-04-21 16:46:34 -07:00
|
|
|
|
2019-04-26 12:40:29 -07:00
|
|
|
var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
|
|
|
|
errdefer tree_arena.deinit();
|
|
|
|
const arena = &tree_arena.allocator;
|
|
|
|
|
|
|
|
const root_node = try arena.create(ast.Node.Root);
|
|
|
|
root_node.* = ast.Node.Root{
|
|
|
|
.base = ast.Node{ .id = ast.Node.Id.Root },
|
|
|
|
.decls = ast.Node.Root.DeclList.init(arena),
|
|
|
|
.doc_comments = null,
|
|
|
|
// initialized with the eof token at the end
|
|
|
|
.eof_token = undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
const tree = try arena.create(ast.Tree);
|
|
|
|
tree.* = ast.Tree{
|
|
|
|
.source = undefined, // need to use Buffer.toOwnedSlice later
|
|
|
|
.root_node = root_node,
|
|
|
|
.arena_allocator = tree_arena,
|
|
|
|
.tokens = ast.Tree.TokenList.init(arena),
|
|
|
|
.errors = ast.Tree.ErrorList.init(arena),
|
|
|
|
};
|
|
|
|
|
|
|
|
var source_buffer = try std.Buffer.initSize(arena, 0);
|
|
|
|
|
2019-04-29 21:21:45 -07:00
|
|
|
var context = Context{
|
|
|
|
.tree = tree,
|
|
|
|
.source_buffer = &source_buffer,
|
|
|
|
.err = undefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
|
|
|
|
return context.err;
|
|
|
|
}
|
2019-04-26 12:40:29 -07:00
|
|
|
|
2019-04-29 21:21:45 -07:00
|
|
|
try appendToken(&context, .Eof, "");
|
2019-04-26 12:40:29 -07:00
|
|
|
tree.source = source_buffer.toOwnedSlice();
|
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2019-04-29 21:21:45 -07:00
|
|
|
extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool {
|
|
|
|
const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
|
|
|
|
declVisitor(c, decl) catch |err| {
|
|
|
|
c.err = err;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
|
|
|
|
switch (ZigClangDecl_getKind(decl)) {
|
|
|
|
.Function => {
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate function decl");
|
|
|
|
},
|
|
|
|
.Typedef => {
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate typedef");
|
|
|
|
},
|
|
|
|
.Enum => {
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate enum");
|
|
|
|
},
|
|
|
|
.Record => {
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate struct");
|
|
|
|
},
|
|
|
|
.Var => {
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate variable");
|
|
|
|
},
|
|
|
|
else => {
|
|
|
|
// TODO emit_warning(c, bitcast(decl->getLocation()), "ignoring %s decl", decl->getDeclKindName());
|
|
|
|
try appendToken(c, .LineComment, "// TODO translate unknown decl");
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn appendToken(c: *Context, token_id: Token.Id, src_text: []const u8) !void {
|
|
|
|
const start_index = c.source_buffer.len();
|
|
|
|
try c.source_buffer.append(src_text);
|
|
|
|
const end_index = c.source_buffer.len();
|
|
|
|
const new_token = try c.tree.tokens.addOne();
|
2019-04-26 12:40:29 -07:00
|
|
|
new_token.* = Token{
|
|
|
|
.id = token_id,
|
|
|
|
.start = start_index,
|
|
|
|
.end = end_index,
|
|
|
|
};
|
2019-04-29 21:21:45 -07:00
|
|
|
try c.source_buffer.appendByte('\n');
|
stage1 is now a hybrid of C++ and Zig
This modifies the build process of Zig to put all of the source files
into libcompiler.a, except main.cpp and userland.cpp.
Next, the build process links main.cpp, userland.cpp, and libcompiler.a
into zig1. userland.cpp is a shim for functions that will later be
replaced with self-hosted implementations.
Next, the build process uses zig1 to build src-self-hosted/stage1.zig
into libuserland.a, which does not depend on any of the things that
are shimmed in userland.cpp, such as translate-c.
Finally, the build process re-links main.cpp and libcompiler.a, except
with libuserland.a instead of userland.cpp. Now the shims are replaced
with .zig code. This provides all of the Zig standard library to the
stage1 C++ compiler, and enables us to move certain things to userland,
such as translate-c.
As a proof of concept I have made the `zig zen` command use text defined
in userland. I added `zig translate-c-2` which is a work-in-progress
reimplementation of translate-c in userland, which currently calls
`std.debug.panic("unimplemented")` and you can see the stack trace makes
it all the way back into the C++ main() function (Thanks LemonBoy for
improving that!).
This could potentially let us move other things into userland, such as
hashing algorithms, the entire cache system, .d file parsing, pretty
much anything that libuserland.a itself doesn't need to depend on.
This can also let us have `zig fmt` in stage1 without the overhead
of child process execution, and without the initial compilation delay
before it gets cached.
See #1964
2019-04-16 13:47:47 -07:00
|
|
|
}
|
2019-04-21 16:37:39 -07:00
|
|
|
|
|
|
|
pub fn freeErrors(errors: []ClangErrMsg) void {
|
|
|
|
ZigClangErrorMsg_delete(errors.ptr, errors.len);
|
|
|
|
}
|