authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-10 17:44:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-10 17:44:47-04:00
log82219b1fd5018a961726847bf42dfc1d33ec3aeb
tree9f9059ca462b8c71dfe4a07d8a424d9f9152f36b
parent2933d6b8489b8dc5c07bfb503578b12d0d783350
signature Commit is signed but in an unrecognized format.

translate-c: better handling of restore points


2 files changed, 62 insertions(+), 84 deletions(-)

src-self-hosted/translate_c.zig+48-46
...@@ -208,14 +208,14 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {...@@ -208,14 +208,14 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
208208
209fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {209fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
210 if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice210 if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice
211211 const rp = makeRestorePoint(c);
212 const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));212 const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));
213 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);213 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
214 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);214 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
215 const fn_type = ZigClangQualType_getTypePtr(fn_qt);215 const fn_type = ZigClangQualType_getTypePtr(fn_qt);
216 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {216 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
217 .FunctionProto => transFnProto(217 .FunctionProto => transFnProto(
218 c,218 rp,
219 @ptrCast(*const ZigClangFunctionProtoType, fn_type),219 @ptrCast(*const ZigClangFunctionProtoType, fn_type),
220 fn_decl_loc,220 fn_decl_loc,
221 fn_decl,221 fn_decl,
...@@ -242,32 +242,35 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {...@@ -242,32 +242,35 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
242 try c.tree.root_node.decls.push(decl_node);242 try c.tree.root_node.decls.push(decl_node);
243}243}
244244
245fn transQualType(c: *Context, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {245fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) Error!*ast.Node {
246 return transType(c, ZigClangQualType_getTypePtr(qt), source_loc);246 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
247}
248
249fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType {
250 const canon = ZigClangQualType_getCanonicalType(qt);
251 return ZigClangQualType_getTypePtr(canon);
247}252}
248253
249const RestorePoint = struct {254const RestorePoint = struct {
250 context: *Context,255 c: *Context,
251 token_index: ast.TokenIndex,256 token_index: ast.TokenIndex,
252 src_buf_index: usize,257 src_buf_index: usize,
253258
254 fn activate(self: RestorePoint) void {259 fn activate(self: RestorePoint) void {
255 self.context.tree.tokens.shrink(self.token_index);260 self.c.tree.tokens.shrink(self.token_index);
256 self.context.source_buffer.shrink(self.src_buf_index);261 self.c.source_buffer.shrink(self.src_buf_index);
257 }262 }
258};263};
259264
260fn makeRestorePoint(c: *Context) RestorePoint {265fn makeRestorePoint(c: *Context) RestorePoint {
261 return RestorePoint{266 return RestorePoint{
262 .context = c,267 .c = c,
263 .token_index = c.tree.tokens.len,268 .token_index = c.tree.tokens.len,
264 .src_buf_index = c.source_buffer.len(),269 .src_buf_index = c.source_buffer.len(),
265 };270 };
266}271}
267272
268fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) !*ast.Node {273fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSourceLocation) Error!*ast.Node {
269 const rp = makeRestorePoint(c);
270
271 switch (ZigClangType_getTypeClass(ty)) {274 switch (ZigClangType_getTypeClass(ty)) {
272 .Builtin => {275 .Builtin => {
273 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);276 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
...@@ -275,23 +278,26 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc...@@ -275,23 +278,26 @@ fn transType(c: *Context, ty: *const ZigClangType, source_loc: ZigClangSourceLoc
275 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"),278 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type"),
276 }279 }
277 },280 },
278 .FunctionProto => return transFnProto(c, @ptrCast(*const ZigClangFunctionType, ty), source_loc, null, false),281 .FunctionProto => {
282 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
283 const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, null);
284 return &fn_proto.base;
285 },
279 else => {286 else => {
280 const type_name = c.str(ZigClangType_getTypeClassName(ty));287 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
281 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name);288 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name);
282 },289 },
283 }290 }
284}291}
285292
286fn transFnProto(293fn transFnProto(
287 c: *Context,294 rp: RestorePoint,
288 fn_proto_ty: *const ZigClangFunctionProtoType,295 fn_proto_ty: *const ZigClangFunctionProtoType,
289 source_loc: ZigClangSourceLocation,296 source_loc: ZigClangSourceLocation,
290 opt_fn_decl: ?*const ZigClangFunctionDecl,297 opt_fn_decl: ?*const ZigClangFunctionDecl,
291 fn_name: ?[]const u8,298 fn_name: ?[]const u8,
292) !*ast.Node.FnProto {299) !*ast.Node.FnProto {
293 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);300 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty);
294 const rp = makeRestorePoint(c);
295 const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) {301 const cc = switch (ZigClangFunctionType_getCallConv(fn_ty)) {
296 .C => CallingConvention.C,302 .C => CallingConvention.C,
297 .X86StdCall => CallingConvention.Stdcall,303 .X86StdCall => CallingConvention.Stdcall,
...@@ -323,13 +329,13 @@ fn transFnProto(...@@ -323,13 +329,13 @@ fn transFnProto(
323 // TODO check for align attribute329 // TODO check for align attribute
324330
325 // extern fn name(...) T331 // extern fn name(...) T
326 const cc_tok = if (cc == .Stdcall) try appendToken(c, .Keyword_stdcallcc, "stdcallcc") else null;332 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
327 const is_export = exp: {333 const is_export = exp: {
328 const fn_decl = opt_fn_decl orelse break :exp false;334 const fn_decl = opt_fn_decl orelse break :exp false;
329 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);335 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
330 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);336 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
331 break :exp switch (storage_class) {337 break :exp switch (storage_class) {
332 .None => switch (c.mode) {338 .None => switch (rp.c.mode) {
333 .import => false,339 .import => false,
334 .translate => has_body,340 .translate => has_body,
335 },341 },
...@@ -340,48 +346,44 @@ fn transFnProto(...@@ -340,48 +346,44 @@ fn transFnProto(
340 };346 };
341 };347 };
342 const extern_export_inline_tok = if (is_export)348 const extern_export_inline_tok = if (is_export)
343 try appendToken(c, .Keyword_export, "export")349 try appendToken(rp.c, .Keyword_export, "export")
344 else if (cc == .C)350 else if (cc == .C)
345 try appendToken(c, .Keyword_extern, "extern")351 try appendToken(rp.c, .Keyword_extern, "extern")
346 else352 else
347 null;353 null;
348 const fn_tok = try appendToken(c, .Keyword_fn, "fn");354 const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
349 const name_tok = if (fn_name) |n| try appendToken(c, .Identifier, "{}", n) else null;355 const name_tok = if (fn_name) |n| try appendToken(rp.c, .Identifier, "{}", n) else null;
350 const lparen_tok = try appendToken(c, .LParen, "(");356 const lparen_tok = try appendToken(rp.c, .LParen, "(");
351 const var_args_tok = if (is_var_args) try appendToken(c, .Ellipsis3, "...") else null;357 const var_args_tok = if (is_var_args) try appendToken(rp.c, .Ellipsis3, "...") else null;
352 const rparen_tok = try appendToken(c, .RParen, ")");358 const rparen_tok = try appendToken(rp.c, .RParen, ")");
353359
354 const return_type_node = blk: {360 const return_type_node = blk: {
355 if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) {361 if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) {
356 break :blk try appendIdentifier(c, "noreturn");362 break :blk try appendIdentifier(rp.c, "noreturn");
357 } else {363 } else {
358 return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: non-noreturn FunctionProto return type");364 const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
359 //proto_node->data.fn_proto.return_type = trans_qual_type(c,365 if (ZigClangType_isVoidType(qualTypeCanon(return_qt))) {
360 // ZigClangFunctionType_getReturnType(fn_ty), source_loc);366 break :blk try appendIdentifier(rp.c, "void");
361 //if (proto_node->data.fn_proto.return_type == nullptr) {367 } else {
362 // emit_warning(c, source_loc, "unsupported function proto return type");368 break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
363 // return nullptr;369 error.UnsupportedType => {
364 //}370 try emitWarning(rp.c, source_loc, "unsupported function proto return type");
365 //// convert c_void to actual void (only for return type)371 return err;
366 //// we do want to look at the AstNode instead of ZigClangQualType, because372 },
367 //// if they do something like:373 else => return err,
368 //// typedef Foo void;374 };
369 //// void foo(void) -> Foo;375 }
370 //// we want to keep the return type AST node.
371 //if (is_c_void_type(proto_node->data.fn_proto.return_type)) {
372 // proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void");
373 //}
374 }376 }
375 };377 };
376378
377 const fn_proto = try c.a().create(ast.Node.FnProto);379 const fn_proto = try rp.c.a().create(ast.Node.FnProto);
378 fn_proto.* = ast.Node.FnProto{380 fn_proto.* = ast.Node.FnProto{
379 .base = ast.Node{ .id = ast.Node.Id.FnProto },381 .base = ast.Node{ .id = ast.Node.Id.FnProto },
380 .doc_comments = null,382 .doc_comments = null,
381 .visib_token = null,383 .visib_token = null,
382 .fn_token = fn_tok,384 .fn_token = fn_tok,
383 .name_token = name_tok,385 .name_token = name_tok,
384 .params = ast.Node.FnProto.ParamList.init(c.a()),386 .params = ast.Node.FnProto.ParamList.init(rp.c.a()),
385 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },387 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },
386 .var_args_token = var_args_tok,388 .var_args_token = var_args_tok,
387 .extern_export_inline_token = extern_export_inline_tok,389 .extern_export_inline_token = extern_export_inline_tok,
...@@ -396,14 +398,14 @@ fn transFnProto(...@@ -396,14 +398,14 @@ fn transFnProto(
396}398}
397399
398fn revertAndWarn(400fn revertAndWarn(
399 restore_point: RestorePoint,401 rp: RestorePoint,
400 err: var,402 err: var,
401 source_loc: ZigClangSourceLocation,403 source_loc: ZigClangSourceLocation,
402 comptime format: []const u8,404 comptime format: []const u8,
403 args: ...,405 args: ...,
404) (@typeOf(err) || error{OutOfMemory}) {406) (@typeOf(err) || error{OutOfMemory}) {
405 restore_point.activate();407 rp.activate();
406 try emitWarning(restore_point.context, source_loc, format, args);408 try emitWarning(rp.c, source_loc, format, args);
407 return err;409 return err;
408}410}
409411
test/translate_c.zig+14-38
...@@ -2,12 +2,26 @@ const tests = @import("tests.zig");...@@ -2,12 +2,26 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.TranslateCContext) void {4pub fn addCases(cases: *tests.TranslateCContext) void {
5 /////////////// Cases that pass for both stage1/stage2 ////////////////
5 cases.add_both("simple noreturn fn",6 cases.add_both("simple noreturn fn",
6 \\void __attribute__((noreturn)) foo(void);7 \\void __attribute__((noreturn)) foo(void);
7 ,8 ,
8 \\extern fn foo() noreturn;9 \\extern fn foo() noreturn;
9 );10 );
1011
12 /////////////// Cases that pass for only stage2 ////////////////
13 // (none)
14
15 /////////////// Cases that pass for only stage1 ////////////////
16
17 cases.addC("Parameterless function prototypes",
18 \\void foo() {}
19 \\void bar(void) {}
20 ,
21 \\pub export fn foo() void {}
22 \\pub export fn bar() void {}
23 );
24
11 cases.add("macro with left shift",25 cases.add("macro with left shift",
12 \\#define REDISMODULE_READ (1<<0)26 \\#define REDISMODULE_READ (1<<0)
13 ,27 ,
...@@ -1523,14 +1537,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1523,14 +1537,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1523 \\}1537 \\}
1524 );1538 );
15251539
1526 cases.addC("Parameterless function prototypes",
1527 \\void foo() {}
1528 \\void bar(void) {}
1529 ,
1530 \\pub export fn foo() void {}
1531 \\pub export fn bar() void {}
1532 );
1533
1534 cases.addC(1540 cases.addC(
1535 "u integer suffix after 0 (zero) in macro definition",1541 "u integer suffix after 0 (zero) in macro definition",
1536 "#define ZERO 0U",1542 "#define ZERO 0U",
...@@ -1667,34 +1673,4 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1667,34 +1673,4 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1667 \\ }1673 \\ }
1668 \\}1674 \\}
1669 );1675 );
1670
1671 // cases.add("empty array with initializer",
1672 // "int a[4] = {};"
1673 // ,
1674 // "pub var a: [4]c_int = [1]c_int{0} ** 4;"
1675 // );
1676
1677 // cases.add("array with initialization",
1678 // "int a[4] = {1, 2, 3, 4};"
1679 // ,
1680 // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};"
1681 // );
1682
1683 // cases.add("array with incomplete initialization",
1684 // "int a[4] = {3, 4};"
1685 // ,
1686 // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);"
1687 // );
1688
1689 // cases.add("2D array with initialization",
1690 // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };"
1691 // ,
1692 // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};"
1693 // );
1694
1695 // cases.add("2D array with incomplete initialization",
1696 // "int a[3][3] = { {1, 2}, {4, 5, 6} };"
1697 // ,
1698 // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};"
1699 // );
1700}1676}