authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-10 22:30:19+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:40:05+02:00
log66dd64ec15d787bb43cb0ab1169e8bac6cfe762e
tree81c258e64b5c9052a88ccdf279e8e1d7fe69ff48
parentd8b9fca0b1c8929be99b6dff8f961afbe2fe2e3c
signature Commit is signed but in an unrecognized format.

translate-c: convert most control flow


2 files changed, 56 insertions(+), 74 deletions(-)

src/translate_c.zig+49-74
...@@ -107,6 +107,7 @@ const Scope = struct {...@@ -107,6 +107,7 @@ const Scope = struct {
107 // do while, we want to put `if (cond) break;` at the end.107 // do while, we want to put `if (cond) break;` at the end.
108 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);108 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
109 const stmts = try c.arena.alloc(Node, alloc_len);109 const stmts = try c.arena.alloc(Node, alloc_len);
110 stmts.len -= 1;
110 mem.copy(Node, stmts, self.statements.items);111 mem.copy(Node, stmts, self.statements.items);
111 return Node.block.create(c.arena, .{112 return Node.block.create(c.arena, .{
112 .lable = self.label,113 .lable = self.label,
...@@ -1748,7 +1749,7 @@ fn transCCast(...@@ -1748,7 +1749,7 @@ fn transCCast(
1748 if (dst_type.eq(src_type)) return expr;1749 if (dst_type.eq(src_type)) return expr;
1749 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))1750 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
1750 return transCPtrCast(c, loc, dst_type, src_type, expr);1751 return transCPtrCast(c, loc, dst_type, src_type, expr);
1751 1752
1752 const dst_node = try transQualType(c, dst_type, loc);1753 const dst_node = try transQualType(c, dst_type, loc);
1753 if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {1754 if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
1754 // 1. If src_type is an enum, determine the underlying signed int type1755 // 1. If src_type is an enum, determine the underlying signed int type
...@@ -1931,7 +1932,7 @@ fn transInitListExprArray(...@@ -1931,7 +1932,7 @@ fn transInitListExprArray(
1931 if (all_count == 0) {1932 if (all_count == 0) {
1932 return Node.empty_array.create(c.arena, try transQualType(c, child_qt, source_loc));1933 return Node.empty_array.create(c.arena, try transQualType(c, child_qt, source_loc));
1933 }1934 }
1934 1935
1935 const ty_node = try transType(ty);1936 const ty_node = try transType(ty);
1936 const init_node = if (init_count != 0) blk: {1937 const init_node = if (init_count != 0) blk: {
1937 const init_list = try c.arena.alloc(Node, init_count);1938 const init_list = try c.arena.alloc(Node, init_count);
...@@ -2058,14 +2059,12 @@ fn transImplicitValueInitExpr(...@@ -2058,14 +2059,12 @@ fn transImplicitValueInitExpr(
2058}2059}
20592060
2060fn transIfStmt(2061fn transIfStmt(
2061 rp: RestorePoint,2062 c: *Context,
2062 scope: *Scope,2063 scope: *Scope,
2063 stmt: *const clang.IfStmt,2064 stmt: *const clang.IfStmt,
2064) TransError!*ast.Node {2065) TransError!Node {
2065 // if (c) t2066 // if (c) t
2066 // if (c) t else e2067 // if (c) t else e
2067 const if_node = try transCreateNodeIf(rp.c);
2068
2069 var cond_scope = Scope.Condition{2068 var cond_scope = Scope.Condition{
2070 .base = .{2069 .base = .{
2071 .parent = scope,2070 .parent = scope,
...@@ -2074,26 +2073,21 @@ fn transIfStmt(...@@ -2074,26 +2073,21 @@ fn transIfStmt(
2074 };2073 };
2075 defer cond_scope.deinit();2074 defer cond_scope.deinit();
2076 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());2075 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
2077 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);2076 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value);
2078 _ = try appendToken(rp.c, .RParen, ")");
2079
2080 if_node.body = try transStmt(rp, scope, stmt.getThen(), .unused, .r_value);
20812077
2082 if (stmt.getElse()) |expr| {2078 const then_body = try transStmt(c, scope, stmt.getThen(), .unused, .r_value);
2083 if_node.@"else" = try transCreateNodeElse(rp.c);2079 const else_body = if (stmt.getElse()) |expr|
2084 if_node.@"else".?.body = try transStmt(rp, scope, expr, .unused, .r_value);2080 try transStmt(c, scope, expr, .unused, .r_value)
2085 }2081 else
2086 _ = try appendToken(rp.c, .Semicolon, ";");2082 null;
2087 return &if_node.base;2083 return Node.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body });
2088}2084}
20892085
2090fn transWhileLoop(2086fn transWhileLoop(
2091 rp: RestorePoint,2087 c: *Context,
2092 scope: *Scope,2088 scope: *Scope,
2093 stmt: *const clang.WhileStmt,2089 stmt: *const clang.WhileStmt,
2094) TransError!*ast.Node {2090) TransError!Node {
2095 const while_node = try transCreateNodeWhile(rp.c);
2096
2097 var cond_scope = Scope.Condition{2091 var cond_scope = Scope.Condition{
2098 .base = .{2092 .base = .{
2099 .parent = scope,2093 .parent = scope,
...@@ -2102,35 +2096,28 @@ fn transWhileLoop(...@@ -2102,35 +2096,28 @@ fn transWhileLoop(
2102 };2096 };
2103 defer cond_scope.deinit();2097 defer cond_scope.deinit();
2104 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());2098 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
2105 while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);2099 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value);
2106 _ = try appendToken(rp.c, .RParen, ")");
21072100
2108 var loop_scope = Scope{2101 var loop_scope = Scope{
2109 .parent = scope,2102 .parent = scope,
2110 .id = .Loop,2103 .id = .Loop,
2111 };2104 };
2112 while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2105 const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
2113 _ = try appendToken(rp.c, .Semicolon, ";");2106 return Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null });
2114 return &while_node.base;
2115}2107}
21162108
2117fn transDoWhileLoop(2109fn transDoWhileLoop(
2118 rp: RestorePoint,2110 c: *Context,
2119 scope: *Scope,2111 scope: *Scope,
2120 stmt: *const clang.DoStmt,2112 stmt: *const clang.DoStmt,
2121) TransError!*ast.Node {2113) TransError!Node {
2122 const while_node = try transCreateNodeWhile(rp.c);
2123
2124 while_node.condition = try transCreateNodeBoolLiteral(rp.c, true);
2125 _ = try appendToken(rp.c, .RParen, ")");
2126 var new = false;
2127 var loop_scope = Scope{2114 var loop_scope = Scope{
2128 .parent = scope,2115 .parent = scope,
2129 .id = .Loop,2116 .id = .Loop,
2130 };2117 };
21312118
2132 // if (!cond) break;2119 // if (!cond) break;
2133 const if_node = try transCreateNodeIf(rp.c);2120 const if_node = try transCreateNodeIf(c);
2134 var cond_scope = Scope.Condition{2121 var cond_scope = Scope.Condition{
2135 .base = .{2122 .base = .{
2136 .parent = scope,2123 .parent = scope,
...@@ -2138,12 +2125,8 @@ fn transDoWhileLoop(...@@ -2138,12 +2125,8 @@ fn transDoWhileLoop(
2138 },2125 },
2139 };2126 };
2140 defer cond_scope.deinit();2127 defer cond_scope.deinit();
2141 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");2128 const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value);
2142 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value, true);2129 const if_not_break = try Node.if_not_break.create(c.arena, cond);
2143 _ = try appendToken(rp.c, .RParen, ")");
2144 if_node.condition = &prefix_op.base;
2145 if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;
2146 _ = try appendToken(rp.c, .Semicolon, ";");
21472130
2148 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {2131 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
2149 // there's already a block in C, so we'll append our condition to it.2132 // there's already a block in C, so we'll append our condition to it.
...@@ -2156,8 +2139,12 @@ fn transDoWhileLoop(...@@ -2156,8 +2139,12 @@ fn transDoWhileLoop(
2156 // zig: b;2139 // zig: b;
2157 // zig: if (!cond) break;2140 // zig: if (!cond) break;
2158 // zig: }2141 // zig: }
2159 const node = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2142 const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
2160 break :blk node.castTag(.Block).?;2143 const block = node.castTag(.block);
2144 block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete.
2145 block.data.stmts[block.data.stmts.len - 1] = if_not_break;
2146 break :blk node;
2147
2161 } else blk: {2148 } else blk: {
2162 // the C statement is without a block, so we need to create a block to contain it.2149 // the C statement is without a block, so we need to create a block to contain it.
2163 // c: do2150 // c: do
...@@ -2167,27 +2154,19 @@ fn transDoWhileLoop(...@@ -2167,27 +2154,19 @@ fn transDoWhileLoop(
2167 // zig: a;2154 // zig: a;
2168 // zig: if (!cond) break;2155 // zig: if (!cond) break;
2169 // zig: }2156 // zig: }
2170 new = true;2157 const statements = try c.arena.create(Node, 2);
2171 const block = try rp.c.createBlock(2);2158 statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
2172 block.statements_len = 1; // over-allocated so we can add another below2159 statements[1] = if_not_break;
2173 block.statements()[0] = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2160 break :blk try Node.block.create(c.arena, .{ .label = null, .stmts = statements });
2174 break :blk block;
2175 };2161 };
21762162 return Node.while_true.create(c.arena, body_node);
2177 // In both cases above, we reserved 1 extra statement.
2178 body_node.statements_len += 1;
2179 body_node.statements()[body_node.statements_len - 1] = &if_node.base;
2180 if (new)
2181 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2182 while_node.body = &body_node.base;
2183 return &while_node.base;
2184}2163}
21852164
2186fn transForLoop(2165fn transForLoop(
2187 rp: RestorePoint,2166 c: *Context,
2188 scope: *Scope,2167 scope: *Scope,
2189 stmt: *const clang.ForStmt,2168 stmt: *const clang.ForStmt,
2190) TransError!*ast.Node {2169) TransError!Node {
2191 var loop_scope = Scope{2170 var loop_scope = Scope{
2192 .parent = scope,2171 .parent = scope,
2193 .id = .Loop,2172 .id = .Loop,
...@@ -2197,9 +2176,9 @@ fn transForLoop(...@@ -2197,9 +2176,9 @@ fn transForLoop(
2197 defer if (block_scope) |*bs| bs.deinit();2176 defer if (block_scope) |*bs| bs.deinit();
21982177
2199 if (stmt.getInit()) |init| {2178 if (stmt.getInit()) |init| {
2200 block_scope = try Scope.Block.init(rp.c, scope, false);2179 block_scope = try Scope.Block.init(c, scope, false);
2201 loop_scope.parent = &block_scope.?.base;2180 loop_scope.parent = &block_scope.?.base;
2202 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);2181 const init_node = try transStmt(c, &block_scope.?.base, init, .unused, .r_value);
2203 try block_scope.?.statements.append(init_node);2182 try block_scope.?.statements.append(init_node);
2204 }2183 }
2205 var cond_scope = Scope.Condition{2184 var cond_scope = Scope.Condition{
...@@ -2210,27 +2189,23 @@ fn transForLoop(...@@ -2210,27 +2189,23 @@ fn transForLoop(
2210 };2189 };
2211 defer cond_scope.deinit();2190 defer cond_scope.deinit();
22122191
2213 const while_node = try transCreateNodeWhile(rp.c);2192 const cond = if (stmt.getCond()) |cond|
2214 while_node.condition = if (stmt.getCond()) |cond|2193 try transBoolExpr(c, &cond_scope.base, cond, .used, .r_value)
2215 try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
2216 else2194 else
2217 try transCreateNodeBoolLiteral(rp.c, true);2195 Node.true_literal.init();
2218 _ = try appendToken(rp.c, .RParen, ")");
22192196
2220 if (stmt.getInc()) |incr| {2197 const cont_expr = if (stmt.getInc()) |incr|
2221 _ = try appendToken(rp.c, .Colon, ":");2198 try transExpr(c, &cond_scope.base, incr, .unused, .r_value)
2222 _ = try appendToken(rp.c, .LParen, "(");2199 else
2223 while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);2200 null;
2224 _ = try appendToken(rp.c, .RParen, ")");
2225 }
22262201
2227 while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2202 const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
2203 const while_node = try Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr });
2228 if (block_scope) |*bs| {2204 if (block_scope) |*bs| {
2229 try bs.statements.append(&while_node.base);2205 try bs.statements.append(while_node);
2230 return try bs.complete(rp.c);2206 return try bs.complete(c);
2231 } else {2207 } else {
2232 _ = try appendToken(rp.c, .Semicolon, ";");2208 return while_node;
2233 return &while_node.base;
2234 }2209 }
2235}2210}
22362211
src/translate_c/ast.zig+7
...@@ -29,7 +29,11 @@ pub const Node = extern union {...@@ -29,7 +29,11 @@ pub const Node = extern union {
29 char_literal,29 char_literal,
30 identifier,30 identifier,
31 @"if",31 @"if",
32 /// if (!operand) break;
33 if_not_break,
32 @"while",34 @"while",
35 /// while (true) operand
36 while_true,
33 @"switch",37 @"switch",
34 @"continue",38 @"continue",
35 @"break",39 @"break",
...@@ -211,6 +215,8 @@ pub const Node = extern union {...@@ -211,6 +215,8 @@ pub const Node = extern union {
211 .ptr_to_int,215 .ptr_to_int,
212 .enum_to_int,216 .enum_to_int,
213 .empty_array,217 .empty_array,
218 .while_true,
219 .if_not_break,
214 => Payload.UnOp,220 => Payload.UnOp,
215221
216 .add,222 .add,
...@@ -399,6 +405,7 @@ pub const Payload = struct {...@@ -399,6 +405,7 @@ pub const Payload = struct {
399 data: struct {405 data: struct {
400 cond: Node,406 cond: Node,
401 body: Node,407 body: Node,
408 cont_expr: ?Node
402 },409 },
403 };410 };
404411