Skip to content

Commit 5f4c3e6

Browse files
committed
stage2 translate-c: simple function definitions
See #1964
1 parent dbb5da1 commit 5f4c3e6

File tree

6 files changed

+210
-49
lines changed

6 files changed

+210
-49
lines changed

src-self-hosted/clang.zig

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub const struct_ZigClangCStyleCastExpr = @OpaqueType();
1212
pub const struct_ZigClangCallExpr = @OpaqueType();
1313
pub const struct_ZigClangCaseStmt = @OpaqueType();
1414
pub const struct_ZigClangCompoundAssignOperator = @OpaqueType();
15-
pub const struct_ZigClangCompoundStmt = @OpaqueType();
15+
pub const ZigClangCompoundStmt = @OpaqueType();
1616
pub const struct_ZigClangConditionalOperator = @OpaqueType();
1717
pub const struct_ZigClangConstantArrayType = @OpaqueType();
1818
pub const struct_ZigClangContinueStmt = @OpaqueType();
@@ -33,7 +33,7 @@ pub const struct_ZigClangFieldDecl = @OpaqueType();
3333
pub const struct_ZigClangFileID = @OpaqueType();
3434
pub const struct_ZigClangForStmt = @OpaqueType();
3535
pub const struct_ZigClangFullSourceLoc = @OpaqueType();
36-
pub const struct_ZigClangFunctionDecl = @OpaqueType();
36+
pub const ZigClangFunctionDecl = @OpaqueType();
3737
pub const struct_ZigClangFunctionProtoType = @OpaqueType();
3838
pub const struct_ZigClangIfStmt = @OpaqueType();
3939
pub const struct_ZigClangImplicitCastExpr = @OpaqueType();
@@ -488,12 +488,12 @@ pub extern fn ZigClangQualType_isRestrictQualified(arg0: struct_ZigClangQualType
488488
pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass;
489489
pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
490490
pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8;
491-
pub extern fn ZigClangStmt_getBeginLoc(self: ?*const struct_ZigClangStmt) struct_ZigClangSourceLocation;
491+
pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
492492
pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
493493
pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
494494
pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass;
495495
pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType;
496-
pub extern fn ZigClangExpr_getBeginLoc(self: ?*const struct_ZigClangExpr) struct_ZigClangSourceLocation;
496+
pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
497497
pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind;
498498
pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPSInt;
499499
pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint;
@@ -510,11 +510,12 @@ pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_
510510
pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;
511511
pub extern fn ZigClangASTUnit_delete(arg0: ?*struct_ZigClangASTUnit) void;
512512

513-
pub extern fn ZigClangFunctionDecl_getType(self: *const struct_ZigClangFunctionDecl) struct_ZigClangQualType;
514-
pub extern fn ZigClangFunctionDecl_getLocation(self: *const struct_ZigClangFunctionDecl) struct_ZigClangSourceLocation;
515-
pub extern fn ZigClangFunctionDecl_hasBody(self: *const struct_ZigClangFunctionDecl) bool;
516-
pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const struct_ZigClangFunctionDecl) ZigClangStorageClass;
517-
pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const struct_ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl;
513+
pub extern fn ZigClangFunctionDecl_getType(self: *const ZigClangFunctionDecl) struct_ZigClangQualType;
514+
pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl) struct_ZigClangSourceLocation;
515+
pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool;
516+
pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass;
517+
pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl;
518+
pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt;
518519

519520
pub extern fn ZigClangBuiltinType_getKind(self: *const struct_ZigClangBuiltinType) ZigClangBuiltinTypeKind;
520521

@@ -543,7 +544,6 @@ pub const ZigClangCStyleCastExpr = struct_ZigClangCStyleCastExpr;
543544
pub const ZigClangCallExpr = struct_ZigClangCallExpr;
544545
pub const ZigClangCaseStmt = struct_ZigClangCaseStmt;
545546
pub const ZigClangCompoundAssignOperator = struct_ZigClangCompoundAssignOperator;
546-
pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt;
547547
pub const ZigClangConditionalOperator = struct_ZigClangConditionalOperator;
548548
pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType;
549549
pub const ZigClangContinueStmt = struct_ZigClangContinueStmt;
@@ -564,7 +564,6 @@ pub const ZigClangFieldDecl = struct_ZigClangFieldDecl;
564564
pub const ZigClangFileID = struct_ZigClangFileID;
565565
pub const ZigClangForStmt = struct_ZigClangForStmt;
566566
pub const ZigClangFullSourceLoc = struct_ZigClangFullSourceLoc;
567-
pub const ZigClangFunctionDecl = struct_ZigClangFunctionDecl;
568567
pub const ZigClangFunctionProtoType = struct_ZigClangFunctionProtoType;
569568
pub const ZigClangIfStmt = struct_ZigClangIfStmt;
570569
pub const ZigClangImplicitCastExpr = struct_ZigClangImplicitCastExpr;
@@ -860,3 +859,8 @@ pub const ZigClangStorageClass = extern enum {
860859
Auto,
861860
Register,
862861
};
862+
863+
pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt;
864+
865+
pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
866+
pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;

src-self-hosted/translate_c.zig

Lines changed: 156 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
const std = @import("std");
55
const builtin = @import("builtin");
6+
const assert = std.debug.assert;
67
const ast = std.zig.ast;
78
const Token = std.zig.Token;
89
use @import("clang.zig");
@@ -21,6 +22,10 @@ pub const Error = error{
2122
OutOfMemory,
2223
UnsupportedType,
2324
};
25+
pub const TransError = error{
26+
OutOfMemory,
27+
UnsupportedTranslation,
28+
};
2429

2530
const DeclTable = std.HashMap(usize, void, addrHash, addrEql);
2631

@@ -61,6 +66,27 @@ const Scope = struct {
6166

6267
const Block = struct {
6368
base: Scope,
69+
block_node: *ast.Node.Block,
70+
71+
/// Don't forget to set rbrace token later
72+
fn create(c: *Context, parent: *Scope, lbrace_tok: ast.TokenIndex) !*Block {
73+
const block = try c.a().create(Block);
74+
block.* = Block{
75+
.base = Scope{
76+
.id = Id.Block,
77+
.parent = parent,
78+
},
79+
.block_node = try c.a().create(ast.Node.Block),
80+
};
81+
block.block_node.* = ast.Node.Block{
82+
.base = ast.Node{ .id = ast.Node.Id.Block },
83+
.label = null,
84+
.lbrace = lbrace_tok,
85+
.statements = ast.Node.Block.StatementList.init(c.a()),
86+
.rbrace = undefined,
87+
};
88+
return block;
89+
}
6490
};
6591

6692
const Root = struct {
@@ -72,6 +98,12 @@ const Scope = struct {
7298
};
7399
};
74100

101+
const TransResult = struct {
102+
node: *ast.Node,
103+
node_scope: *Scope,
104+
child_scope: *Scope,
105+
};
106+
75107
const Context = struct {
76108
tree: *ast.Tree,
77109
source_buffer: *std.Buffer,
@@ -170,6 +202,14 @@ pub fn translate(
170202

171203
_ = try appendToken(&context, .Eof, "");
172204
tree.source = source_buffer.toOwnedSlice();
205+
if (false) {
206+
std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source);
207+
var i: usize = 0;
208+
while (i < tree.tokens.len) : (i += 1) {
209+
const token = tree.tokens.at(i);
210+
std.debug.warn("{}\n", token);
211+
}
212+
}
173213
return tree;
174214
}
175215

@@ -213,29 +253,107 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
213253
const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
214254
const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
215255
const fn_type = ZigClangQualType_getTypePtr(fn_qt);
256+
var scope = &c.global_scope.base;
257+
const decl_ctx = FnDeclContext{
258+
.fn_name = fn_name,
259+
.has_body = ZigClangFunctionDecl_hasBody(fn_decl),
260+
.storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl),
261+
.scope = &scope,
262+
};
216263
const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
217-
.FunctionProto => transFnProto(
218-
rp,
219-
@ptrCast(*const ZigClangFunctionProtoType, fn_type),
220-
fn_decl_loc,
221-
fn_decl,
222-
fn_name,
223-
) catch |err| switch (err) {
224-
error.UnsupportedType => {
225-
return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function");
226-
},
227-
else => return err,
264+
.FunctionProto => blk: {
265+
const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type);
266+
break :blk transFnProto(rp, fn_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) {
267+
error.UnsupportedType => {
268+
return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function");
269+
},
270+
error.OutOfMemory => return error.OutOfMemory,
271+
};
228272
},
229273
.FunctionNoProto => return failDecl(c, fn_decl_loc, fn_name, "TODO support functions with no prototype"),
230274
else => unreachable,
231275
};
232276

233-
if (!ZigClangFunctionDecl_hasBody(fn_decl)) {
277+
if (!decl_ctx.has_body) {
234278
const semi_tok = try appendToken(c, .Semicolon, ";");
235279
return addTopLevelDecl(c, fn_name, &proto_node.base);
236280
}
237281

238-
try emitWarning(c, fn_decl_loc, "TODO implement function body translation");
282+
// actual function definition with body
283+
const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);
284+
const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) {
285+
error.OutOfMemory => return error.OutOfMemory,
286+
error.UnsupportedTranslation => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"),
287+
};
288+
assert(result.node.id == ast.Node.Id.Block);
289+
proto_node.body_node = result.node;
290+
291+
return addTopLevelDecl(c, fn_name, &proto_node.base);
292+
}
293+
294+
const ResultUsed = enum {
295+
used,
296+
unused,
297+
};
298+
299+
const LRValue = enum {
300+
l_value,
301+
r_value,
302+
};
303+
304+
fn transStmt(
305+
rp: RestorePoint,
306+
scope: *Scope,
307+
stmt: *const ZigClangStmt,
308+
result_used: ResultUsed,
309+
lrvalue: LRValue,
310+
) !TransResult {
311+
const sc = ZigClangStmt_getStmtClass(stmt);
312+
switch (sc) {
313+
.CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)),
314+
else => {
315+
return revertAndWarn(
316+
rp,
317+
error.UnsupportedTranslation,
318+
ZigClangStmt_getBeginLoc(stmt),
319+
"TODO implement translation of stmt class {}",
320+
@tagName(sc),
321+
);
322+
},
323+
}
324+
}
325+
326+
fn transCompoundStmtInline(
327+
rp: RestorePoint,
328+
parent_scope: *Scope,
329+
stmt: *const ZigClangCompoundStmt,
330+
block_node: *ast.Node.Block,
331+
) TransError!TransResult {
332+
var it = ZigClangCompoundStmt_body_begin(stmt);
333+
const end_it = ZigClangCompoundStmt_body_end(stmt);
334+
var scope = parent_scope;
335+
while (it != end_it) : (it += 1) {
336+
const result = try transStmt(rp, scope, it.*, .unused, .r_value);
337+
scope = result.child_scope;
338+
try block_node.statements.push(result.node);
339+
}
340+
return TransResult{
341+
.node = &block_node.base,
342+
.child_scope = scope,
343+
.node_scope = scope,
344+
};
345+
}
346+
347+
fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) !TransResult {
348+
const lbrace_tok = try appendToken(rp.c, .LBrace, "{");
349+
const block_scope = try Scope.Block.create(rp.c, scope, lbrace_tok);
350+
const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
351+
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
352+
return TransResult{
353+
.node = &block_scope.block_node.base,
354+
.node_scope = inline_result.node_scope,
355+
.child_scope = inline_result.child_scope,
356+
};
239357
}
240358

241359
fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
@@ -299,7 +417,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
299417
},
300418
.FunctionProto => {
301419
const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
302-
const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, null);
420+
const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null);
303421
return &fn_proto.base;
304422
},
305423
else => {
@@ -309,12 +427,18 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
309427
}
310428
}
311429

430+
const FnDeclContext = struct {
431+
fn_name: []const u8,
432+
has_body: bool,
433+
storage_class: ZigClangStorageClass,
434+
scope: **Scope,
435+
};
436+
312437
fn transFnProto(
313438
rp: RestorePoint,
314439
fn_proto_ty: *const ZigClangFunctionProtoType,
315440
source_loc: ZigClangSourceLocation,
316-
opt_fn_decl: ?*const ZigClangFunctionDecl,
317-
fn_name: ?[]const u8,
441+
fn_decl_context: ?FnDeclContext,
318442
) !*ast.Node.FnProto {
319443
const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);
320444
const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) {
@@ -351,13 +475,11 @@ fn transFnProto(
351475
const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub");
352476
const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
353477
const is_export = exp: {
354-
const fn_decl = opt_fn_decl orelse break :exp false;
355-
const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
356-
const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
357-
break :exp switch (storage_class) {
478+
const decl_ctx = fn_decl_context orelse break :exp false;
479+
break :exp switch (decl_ctx.storage_class) {
358480
.None => switch (rp.c.mode) {
359481
.import => false,
360-
.translate => has_body,
482+
.translate => decl_ctx.has_body,
361483
},
362484
.Extern, .Static => false,
363485
.PrivateExtern => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported storage class: private extern"),
@@ -372,7 +494,7 @@ fn transFnProto(
372494
else
373495
null;
374496
const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
375-
const name_tok = if (fn_name) |n| try appendToken(rp.c, .Identifier, "{}", n) else null;
497+
const name_tok = if (fn_decl_context) |ctx| try appendToken(rp.c, .Identifier, ctx.fn_name) else null;
376498
const lparen_tok = try appendToken(rp.c, .LParen, "(");
377499
const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null;
378500
const rparen_tok = try appendToken(rp.c, .RParen, ")");
@@ -390,7 +512,7 @@ fn transFnProto(
390512
try emitWarning(rp.c, source_loc, "unsupported function proto return type");
391513
return err;
392514
},
393-
else => return err,
515+
error.OutOfMemory => return error.OutOfMemory,
394516
};
395517
}
396518
}
@@ -430,17 +552,17 @@ fn revertAndWarn(
430552
}
431553

432554
fn emitWarning(c: *Context, loc: ZigClangSourceLocation, comptime format: []const u8, args: ...) !void {
433-
_ = try appendToken(c, .LineComment, "// {}: warning: " ++ format, c.locStr(loc), args);
555+
_ = try appendTokenFmt(c, .LineComment, "// {}: warning: " ++ format, c.locStr(loc), args);
434556
}
435557

436558
fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime format: []const u8, args: ...) !void {
437559
// const name = @compileError(msg);
438560
const const_tok = try appendToken(c, .Keyword_const, "const");
439-
const name_tok = try appendToken(c, .Identifier, "{}", name);
561+
const name_tok = try appendToken(c, .Identifier, name);
440562
const eq_tok = try appendToken(c, .Equal, "=");
441563
const builtin_tok = try appendToken(c, .Builtin, "@compileError");
442564
const lparen_tok = try appendToken(c, .LParen, "(");
443-
const msg_tok = try appendToken(c, .StringLiteral, "\"" ++ format ++ "\"", args);
565+
const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args);
444566
const rparen_tok = try appendToken(c, .RParen, ")");
445567
const semi_tok = try appendToken(c, .Semicolon, ";");
446568

@@ -480,16 +602,20 @@ fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime
480602
try c.tree.root_node.decls.push(&var_decl_node.base);
481603
}
482604

483-
fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, args: ...) !ast.TokenIndex {
605+
fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
606+
return appendTokenFmt(c, token_id, "{}", bytes);
607+
}
608+
609+
fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: ...) !ast.TokenIndex {
484610
const S = struct {
485-
fn callback(context: *Context, bytes: []const u8) Error!void {
611+
fn callback(context: *Context, bytes: []const u8) error{OutOfMemory}!void {
486612
return context.source_buffer.append(bytes);
487613
}
488614
};
489615
const start_index = c.source_buffer.len();
490616
errdefer c.source_buffer.shrink(start_index);
491617

492-
try std.fmt.format(c, Error, S.callback, format, args);
618+
try std.fmt.format(c, error{OutOfMemory}, S.callback, format, args);
493619
const end_index = c.source_buffer.len();
494620
const token_index = c.tree.tokens.len;
495621
const new_token = try c.tree.tokens.addOne();
@@ -506,7 +632,7 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg
506632
}
507633

508634
fn appendIdentifier(c: *Context, name: []const u8) !*ast.Node {
509-
const token_index = try appendToken(c, .Identifier, "{}", name);
635+
const token_index = try appendToken(c, .Identifier, name);
510636
const identifier = try c.a().create(ast.Node.Identifier);
511637
identifier.* = ast.Node.Identifier{
512638
.base = ast.Node{ .id = ast.Node.Id.Identifier },

0 commit comments

Comments
 (0)