authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-14 16:32:31+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:40:42+02:00
log62162a07171ccbdb753650205880c3745a599366
tree456bf0bb4060bbcc9c054523f5bcdf95e79b353b
parentc4dfabf4dcfc29f48356e3c5f762f1ca2c21f088
signature Commit is signed but in an unrecognized format.

translate-c: render control flow


2 files changed, 256 insertions(+), 36 deletions(-)

src/translate_c.zig+28-13
......@@ -36,6 +36,7 @@ const Scope = struct {
3636 root,
3737 condition,
3838 loop,
39 do_loop,
3940 };
4041
4142 /// Represents an in-progress Node.Switch. This struct is stack-allocated.
......@@ -103,15 +104,22 @@ const Scope = struct {
103104 }
104105
105106 fn complete(self: *Block, c: *Context) !Node {
106 // We reserve 1 extra statement if the parent is a Loop. This is in case of
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);
109 var stmts = try c.arena.alloc(Node, alloc_len);
110 stmts.len = self.statements.items.len;
111 mem.copy(Node, stmts, self.statements.items);
107 if (self.base.parent.?.id == .do_loop) {
108 // We reserve 1 extra statement if the parent is a do_loop. This is in case of
109 // do while, we want to put `if (cond) break;` at the end.
110 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .do_loop);
111 var stmts = try c.arena.alloc(Node, alloc_len);
112 stmts.len = self.statements.items.len;
113 mem.copy(Node, stmts, self.statements.items);
114 return Tag.block.create(c.arena, .{
115 .label = self.label,
116 .stmts = stmts,
117 });
118 }
119 if (self.statements.items.len == 0) return Tag.empty_block.init();
112120 return Tag.block.create(c.arena, .{
113121 .label = self.label,
114 .stmts = stmts,
122 .stmts = try c.arena.dupe(Node, self.statements.items),
115123 });
116124 }
117125
......@@ -222,7 +230,7 @@ const Scope = struct {
222230 return switch (scope.id) {
223231 .root => return name,
224232 .block => @fieldParentPtr(Block, "base", scope).getAlias(name),
225 .@"switch", .loop, .condition => scope.parent.?.getAlias(name),
233 .@"switch", .loop, .do_loop, .condition => scope.parent.?.getAlias(name),
226234 };
227235 }
228236
......@@ -230,7 +238,7 @@ const Scope = struct {
230238 return switch (scope.id) {
231239 .root => @fieldParentPtr(Root, "base", scope).contains(name),
232240 .block => @fieldParentPtr(Block, "base", scope).contains(name),
233 .@"switch", .loop, .condition => scope.parent.?.contains(name),
241 .@"switch", .loop, .do_loop, .condition => scope.parent.?.contains(name),
234242 };
235243 }
236244
......@@ -240,7 +248,7 @@ const Scope = struct {
240248 switch (scope.id) {
241249 .root => unreachable,
242250 .@"switch" => return scope,
243 .loop => return scope,
251 .loop, .do_loop => return scope,
244252 else => scope = scope.parent.?,
245253 }
246254 }
......@@ -2063,7 +2071,7 @@ fn transDoWhileLoop(
20632071) TransError!Node {
20642072 var loop_scope = Scope{
20652073 .parent = scope,
2066 .id = .loop,
2074 .id = .do_loop,
20672075 };
20682076
20692077 // if (!cond) break;
......@@ -2075,7 +2083,14 @@ fn transDoWhileLoop(
20752083 };
20762084 defer cond_scope.deinit();
20772085 const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used);
2078 const if_not_break = try Tag.if_not_break.create(c.arena, cond);
2086 const if_not_break = switch (cond.tag()) {
2087 .false_literal => try Tag.@"break".create(c.arena, null),
2088 .true_literal => {
2089 const body_node = try transStmt(c, scope, stmt.getBody(), .unused);
2090 return Tag.while_true.create(c.arena, body_node);
2091 },
2092 else => try Tag.if_not_break.create(c.arena, cond),
2093 };
20792094
20802095 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
20812096 // there's already a block in C, so we'll append our condition to it.
......@@ -4099,7 +4114,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
40994114 const br = blk_last.castTag(.break_val).?;
41004115 break :blk br.data.val;
41014116 } else expr;
4102 const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some|
4117 const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some|
41034118 some.data.lhs
41044119 else
41054120 try Tag.typeof.create(c.arena, typeof_arg);
src/translate_c/ast.zig+228-23
......@@ -848,8 +848,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
848848 break :blk try c.addIdentifier(some);
849849 } else 0;
850850 return c.addNode(.{
851 .tag = .identifier,
852 .main_token = try c.addToken(.keyword_break, "break"),
851 .tag = .@"break",
852 .main_token = tok,
853853 .data = .{
854854 .lhs = break_label,
855855 .rhs = 0,
......@@ -864,8 +864,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
864864 break :blk try c.addIdentifier(some);
865865 } else 0;
866866 return c.addNode(.{
867 .tag = .identifier,
868 .main_token = try c.addToken(.keyword_break, "break"),
867 .tag = .@"break",
868 .main_token = tok,
869869 .data = .{
870870 .lhs = break_label,
871871 .rhs = try renderNode(c, payload.val),
......@@ -1183,7 +1183,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
11831183 const l_brace = try c.addToken(.l_brace, "{");
11841184
11851185 const stmt = try renderNode(c, payload);
1186 _ = try c.addToken(.semicolon, ";");
1186 try addSemicolonIfNeeded(c, payload);
11871187
11881188 _ = try c.addToken(.r_brace, "}");
11891189 return c.addNode(.{
......@@ -1207,11 +1207,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12071207 defer stmts.deinit();
12081208 for (payload.stmts) |stmt| {
12091209 const res = try renderNode(c, stmt);
1210 switch (stmt.tag()) {
1211 .warning => continue,
1212 .var_decl, .var_simple => {},
1213 else => _ = try c.addToken(.semicolon, ";"),
1214 }
1210 if (res == 0) continue;
1211 try addSemicolonIfNeeded(c, stmt);
12151212 try stmts.append(res);
12161213 }
12171214 const span = try c.listToSpan(stmts.items);
......@@ -1245,6 +1242,194 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12451242 },
12461243 });
12471244 },
1245 .@"while" => {
1246 const payload = node.castTag(.@"while").?.data;
1247 const while_tok = try c.addToken(.keyword_while, "while");
1248 _ = try c.addToken(.l_paren, "(");
1249 const cond = try renderNode(c, payload.cond);
1250 _ = try c.addToken(.r_paren, ")");
1251
1252 const cont_expr = if (payload.cont_expr) |some| blk: {
1253 _ = try c.addToken(.colon, ":");
1254 _ = try c.addToken(.l_paren, "(");
1255 const res = try renderNode(c, some);
1256 _ = try c.addToken(.r_paren, ")");
1257 break :blk res;
1258 } else 0;
1259 const body = try renderNode(c, payload.body);
1260
1261 if (cont_expr == 0) {
1262 return c.addNode(.{
1263 .tag = .while_simple,
1264 .main_token = while_tok,
1265 .data = .{
1266 .lhs = cond,
1267 .rhs = body,
1268 },
1269 });
1270 } else {
1271 return c.addNode(.{
1272 .tag = .while_cont,
1273 .main_token = while_tok,
1274 .data = .{
1275 .lhs = cond,
1276 .rhs = try c.addExtra(std.zig.ast.Node.WhileCont{
1277 .cont_expr = cont_expr,
1278 .then_expr = body,
1279 }),
1280 },
1281 });
1282 }
1283 },
1284 .while_true => {
1285 const payload = node.castTag(.while_true).?.data;
1286 const while_tok = try c.addToken(.keyword_while, "while");
1287 _ = try c.addToken(.l_paren, "(");
1288 const cond = try c.addNode(.{
1289 .tag = .true_literal,
1290 .main_token = try c.addToken(.keyword_true, "true"),
1291 .data = undefined,
1292 });
1293 _ = try c.addToken(.r_paren, ")");
1294 const body = try renderNode(c, payload);
1295
1296 return c.addNode(.{
1297 .tag = .while_simple,
1298 .main_token = while_tok,
1299 .data = .{
1300 .lhs = cond,
1301 .rhs = body,
1302 },
1303 });
1304 },
1305 .@"if" => {
1306 const payload = node.castTag(.@"if").?.data;
1307 const if_tok = try c.addToken(.keyword_if, "if");
1308 _ = try c.addToken(.l_paren, "(");
1309 const cond = try renderNode(c, payload.cond);
1310 _ = try c.addToken(.r_paren, ")");
1311
1312 const then_expr = try renderNode(c, payload.then);
1313 const else_node = payload.@"else" orelse return c.addNode(.{
1314 .tag = .if_simple,
1315 .main_token = if_tok,
1316 .data = .{
1317 .lhs = cond,
1318 .rhs = then_expr,
1319 },
1320 });
1321 _ = try c.addToken(.keyword_else, "else");
1322 const else_expr = try renderNode(c, else_node);
1323
1324 return c.addNode(.{
1325 .tag = .@"if",
1326 .main_token = if_tok,
1327 .data = .{
1328 .lhs = cond,
1329 .rhs = try c.addExtra(std.zig.ast.Node.If{
1330 .then_expr = then_expr,
1331 .else_expr = else_expr,
1332 }),
1333 },
1334 });
1335 },
1336 .if_not_break => {
1337 const payload = node.castTag(.if_not_break).?.data;
1338 const if_tok = try c.addToken(.keyword_if, "if");
1339 _ = try c.addToken(.l_paren, "(");
1340 const cond = try c.addNode(.{
1341 .tag = .bool_not,
1342 .main_token = try c.addToken(.bang, "!"),
1343 .data = .{
1344 .lhs = try renderNodeGrouped(c, payload),
1345 .rhs = undefined,
1346 },
1347 });
1348 _ = try c.addToken(.r_paren, ")");
1349 const then_expr = try c.addNode(.{
1350 .tag = .@"break",
1351 .main_token = try c.addToken(.keyword_break, "break"),
1352 .data = .{
1353 .lhs = 0,
1354 .rhs = 0,
1355 },
1356 });
1357
1358 return c.addNode(.{
1359 .tag = .if_simple,
1360 .main_token = if_tok,
1361 .data = .{
1362 .lhs = cond,
1363 .rhs = then_expr,
1364 },
1365 });
1366 },
1367 .@"switch" => {
1368 const payload = node.castTag(.@"switch").?.data;
1369 const switch_tok = try c.addToken(.keyword_switch, "switch");
1370 _ = try c.addToken(.l_paren, "(");
1371 const cond = try renderNode(c, payload.cond);
1372 _ = try c.addToken(.r_paren, ")");
1373
1374 _ = try c.addToken(.l_brace, "{");
1375 var cases = try c.gpa.alloc(NodeIndex, payload.cases.len);
1376 defer c.gpa.free(cases);
1377 for (payload.cases) |case, i| {
1378 if (i != 0) _ = try c.addToken(.comma, ",");
1379 cases[i] = try renderNode(c, case);
1380 }
1381 const span = try c.listToSpan(cases);
1382 _ = try c.addToken(.r_brace, "}");
1383 return c.addNode(.{
1384 .tag = .@"switch",
1385 .main_token = switch_tok,
1386 .data = .{
1387 .lhs = cond,
1388 .rhs = try c.addExtra(NodeSubRange{
1389 .start = span.start,
1390 .end = span.end,
1391 }),
1392 },
1393 });
1394 },
1395 .switch_else => {
1396 const payload = node.castTag(.switch_else).?.data;
1397 _ = try c.addToken(.keyword_else, "else");
1398 return c.addNode(.{
1399 .tag = .switch_case_one,
1400 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"),
1401 .data = .{
1402 .lhs = 0,
1403 .rhs = try renderNode(c, payload),
1404 },
1405 });
1406 },
1407 .switch_prong => {
1408 const payload = node.castTag(.switch_prong).?.data;
1409 const item = try renderNode(c, payload.lhs);
1410 return c.addNode(.{
1411 .tag = .switch_case_one,
1412 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"),
1413 .data = .{
1414 .lhs = item,
1415 .rhs = try renderNode(c, payload.rhs),
1416 },
1417 });
1418 },
1419 .opaque_literal => {
1420 const opaque_tok = try c.addToken(.keyword_opaque, "opaque");
1421 _ = try c.addToken(.l_brace, "{");
1422 _ = try c.addToken(.r_brace, "}");
1423
1424 return c.addNode(.{
1425 .tag = .container_decl_two,
1426 .main_token = opaque_tok,
1427 .data = .{
1428 .lhs = 0,
1429 .rhs = 0,
1430 },
1431 });
1432 },
12481433 else => return c.addNode(.{
12491434 .tag = .identifier,
12501435 .main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}),
......@@ -1256,6 +1441,28 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12561441 }
12571442}
12581443
1444fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
1445 switch (node.tag()) {
1446 .warning => unreachable,
1447 .var_decl, .var_simple, .block, .empty_block, .@"switch" => {},
1448 .while_true => {
1449 const payload = node.castTag(.while_true).?.data;
1450 return addSemicolonIfNeeded(c, payload);
1451 },
1452 .@"while" => {
1453 const payload = node.castTag(.@"while").?.data;
1454 return addSemicolonIfNeeded(c, payload.body);
1455 },
1456 .@"if" => {
1457 const payload = node.castTag(.@"if").?.data;
1458 if (payload.@"else") |some|
1459 return addSemicolonIfNeeded(c, some);
1460 return addSemicolonIfNeeded(c, payload.then);
1461 },
1462 else => _ = try c.addToken(.semicolon, ";"),
1463 }
1464}
1465
12591466fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
12601467 switch (node.tag()) {
12611468 .null_literal,
......@@ -1303,19 +1510,19 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
13031510 .optional_type,
13041511 .c_pointer,
13051512 .single_pointer,
1513 .unwrap,
1514 .deref,
1515 .address_of,
1516 .not,
1517 .negate,
1518 .negate_wrap,
1519 .bit_not,
13061520 => {
13071521 // no grouping needed
13081522 return renderNode(c, node);
13091523 },
13101524
1311 .negate,
1312 .negate_wrap,
1313 .bit_not,
13141525 .opaque_literal,
1315 .not,
1316 .address_of,
1317 .unwrap,
1318 .deref,
13191526 .empty_array,
13201527 .block_single,
13211528 .bool_to_int,
......@@ -1407,13 +1614,11 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
14071614
14081615fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
14091616 const payload = @fieldParentPtr(Payload.UnOp, "base", node.ptr_otherwise).data;
1410 const tok = try c.addToken(tok_tag, bytes);
1411 const operand = try renderNodeGrouped(c, payload);
14121617 return c.addNode(.{
14131618 .tag = tag,
1414 .main_token = tok,
1619 .main_token = try c.addToken(tok_tag, bytes),
14151620 .data = .{
1416 .lhs = operand,
1621 .lhs = try renderNodeGrouped(c, payload),
14171622 .rhs = undefined,
14181623 },
14191624 });
......@@ -1508,7 +1713,7 @@ fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex {
15081713 .main_token = lparen,
15091714 .data = .{
15101715 .lhs = lhs,
1511 .rhs = try c.addExtra(std.zig.ast.Node.SubRange{
1716 .rhs = try c.addExtra(NodeSubRange{
15121717 .start = span.start,
15131718 .end = span.end,
15141719 }),
......@@ -1728,7 +1933,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
17281933 .tag = .fn_proto_multi,
17291934 .main_token = fn_token,
17301935 .data = .{
1731 .lhs = try c.addExtra(std.zig.ast.Node.SubRange{
1936 .lhs = try c.addExtra(NodeSubRange{
17321937 .start = span.start,
17331938 .end = span.end,
17341939 }),