From d9527edfe0f017cd397de7ed947e47600092f929 Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 16 Dec 2019 15:22:37 +0200 Subject: [PATCH] translate-c-2 comma operator --- src-self-hosted/translate_c.zig | 75 ++++++++++++++++++++++++++------- test/translate_c.zig | 15 +++++++ 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 54ef53353d..582aca6b88 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -47,7 +47,7 @@ const Scope = struct { Switch, Block, Root, - While, + Condition, FnDef, Ref, }; @@ -65,9 +65,13 @@ const Scope = struct { base: Scope, block_node: *ast.Node.Block, variables: AliasList, + label: ?[]const u8, /// Don't forget to set rbrace token later - fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block { + fn init(c: *Context, parent: *Scope, want_label: bool) !*Block { + // TODO removing `?[]const u8` here causes LLVM error + const label: ?[]const u8 = if (want_label) try std.fmt.allocPrint(c.a(), "blk_{}", .{c.getMangle()}) else null; + const block_node = try transCreateNodeBlock(c, label); const block = try c.a().create(Block); block.* = .{ .base = .{ @@ -76,6 +80,7 @@ const Scope = struct { }, .block_node = block_node, .variables = AliasList.init(c.a()), + .label = label, }; return block; } @@ -120,7 +125,8 @@ const Scope = struct { } }; - const While = struct { + const Condition = struct { + expr: *ast.Node, base: Scope, }; @@ -157,10 +163,19 @@ const Scope = struct { } }; - fn findBlockScope(inner: *Scope) *Scope.Block { + fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block { var scope = inner; - while (true) : (scope = scope.parent orelse unreachable) { - if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope); + while (true) { + switch (scope.id) { + .Root => unreachable, + .Block => return @fieldParentPtr(Block, "base", scope), + .Condition => { + const cond = @fieldParentPtr(Condition, "base", scope); + // comma operator used + return try Block.init(c, scope, true); + }, + else => scope = inner, + } } } @@ -751,7 +766,6 @@ fn transBinaryOperator( .Or, .LAnd, .LOr, - .Comma, => return revertAndWarn( rp, error.UnsupportedTranslation, @@ -759,6 +773,23 @@ fn transBinaryOperator( "TODO: handle more C binary operators: {}", .{op}, ), + .Comma => { + const block_scope = try scope.findBlockScope(rp.c); + + const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value); + try block_scope.block_node.statements.push(lhs); + + const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); + if (block_scope.base.parent == scope) { + const break_node = try transCreateNodeBreak(rp.c, block_scope.label); + _ = try appendToken(rp.c, .Semicolon, ";"); + try block_scope.block_node.statements.push(&break_node.base); + block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + return maybeSuppressResult(rp, scope, result_used, &block_scope.block_node.base); + } else { + return maybeSuppressResult(rp, scope, result_used, rhs); + } + }, .MulAssign, .DivAssign, .RemAssign, @@ -790,11 +821,10 @@ fn transCompoundStmtInline( } fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { - const block_node = try transCreateNodeBlock(rp.c, null); - const block_scope = try Scope.Block.init(rp.c, scope, block_node); - try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); - block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - return &block_node.base; + const block_scope = try Scope.Block.init(rp.c, scope, false); + try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); + block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + return &block_scope.block_node.base; } fn transCStyleCastExprClass( @@ -818,7 +848,7 @@ fn transCStyleCastExprClass( fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { const c = rp.c; - const block_scope = scope.findBlockScope(); + const block_scope = try scope.findBlockScope(c); var it = ZigClangDeclStmt_decl_begin(stmt); const end_it = ZigClangDeclStmt_decl_end(stmt); @@ -927,7 +957,7 @@ fn transImplicitCastExpr( return transExpr(rp, scope, sub_expr, .used, .r_value); }, .NullToPointer => { - return transCreateNodeNullLiteral(rp.c); + return try transCreateNodeNullLiteral(rp.c); }, else => |kind| return revertAndWarn( rp, @@ -1185,7 +1215,7 @@ fn transImplicitValueInitExpr( .Builtin => blk: { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); switch (ZigClangBuiltinType_getKind(builtin_ty)) { - .Bool => return transCreateNodeBoolLiteral(rp.c, false), + .Bool => return try transCreateNodeBoolLiteral(rp.c, false), .Char_U, .UChar, .Char_S, @@ -2046,6 +2076,21 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { return block_node; } +fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression { + const ltoken = try appendToken(c, .Keyword_break, "break"); + const label_node = if (label) |l| blk: { + _ = try appendToken(c, .Colon, ":"); + break :blk try transCreateNodeIdentifier(c, l); + } else null; + const node = try c.a().create(ast.Node.ControlFlowExpression); + node.* = ast.Node.ControlFlowExpression{ + .ltoken = ltoken, + .kind = .{ .Break = label_node }, + .rhs = null, + }; + return node; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, diff --git a/test/translate_c.zig b/test/translate_c.zig index 9a4c364d1d..c856517ac5 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -699,6 +699,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("comma operator", + \\int foo(char c) { + \\ 2, 4; + \\ return 2, 4, 6; + \\} + , &[_][]const u8{ + \\pub export fn foo(c: u8) c_int { + \\ _ = 2; + \\ _ = 4; + \\ _ = 2; + \\ _ = 4; + \\ return 6; + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// if (builtin.os != builtin.Os.windows) {