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 {...@@ -36,6 +36,7 @@ const Scope = struct {
36 root,36 root,
37 condition,37 condition,
38 loop,38 loop,
39 do_loop,
39 };40 };
4041
41 /// Represents an in-progress Node.Switch. This struct is stack-allocated.42 /// Represents an in-progress Node.Switch. This struct is stack-allocated.
...@@ -103,15 +104,22 @@ const Scope = struct {...@@ -103,15 +104,22 @@ const Scope = struct {
103 }104 }
104105
105 fn complete(self: *Block, c: *Context) !Node {106 fn complete(self: *Block, c: *Context) !Node {
106 // We reserve 1 extra statement if the parent is a Loop. This is in case of107 if (self.base.parent.?.id == .do_loop) {
107 // do while, we want to put `if (cond) break;` at the end.108 // We reserve 1 extra statement if the parent is a do_loop. This is in case of
108 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .loop);109 // do while, we want to put `if (cond) break;` at the end.
109 var stmts = try c.arena.alloc(Node, alloc_len);110 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .do_loop);
110 stmts.len = self.statements.items.len;111 var stmts = try c.arena.alloc(Node, alloc_len);
111 mem.copy(Node, stmts, self.statements.items);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();
112 return Tag.block.create(c.arena, .{120 return Tag.block.create(c.arena, .{
113 .label = self.label,121 .label = self.label,
114 .stmts = stmts,122 .stmts = try c.arena.dupe(Node, self.statements.items),
115 });123 });
116 }124 }
117125
...@@ -222,7 +230,7 @@ const Scope = struct {...@@ -222,7 +230,7 @@ const Scope = struct {
222 return switch (scope.id) {230 return switch (scope.id) {
223 .root => return name,231 .root => return name,
224 .block => @fieldParentPtr(Block, "base", scope).getAlias(name),232 .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),
226 };234 };
227 }235 }
228236
...@@ -230,7 +238,7 @@ const Scope = struct {...@@ -230,7 +238,7 @@ const Scope = struct {
230 return switch (scope.id) {238 return switch (scope.id) {
231 .root => @fieldParentPtr(Root, "base", scope).contains(name),239 .root => @fieldParentPtr(Root, "base", scope).contains(name),
232 .block => @fieldParentPtr(Block, "base", scope).contains(name),240 .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),
234 };242 };
235 }243 }
236244
...@@ -240,7 +248,7 @@ const Scope = struct {...@@ -240,7 +248,7 @@ const Scope = struct {
240 switch (scope.id) {248 switch (scope.id) {
241 .root => unreachable,249 .root => unreachable,
242 .@"switch" => return scope,250 .@"switch" => return scope,
243 .loop => return scope,251 .loop, .do_loop => return scope,
244 else => scope = scope.parent.?,252 else => scope = scope.parent.?,
245 }253 }
246 }254 }
...@@ -2063,7 +2071,7 @@ fn transDoWhileLoop(...@@ -2063,7 +2071,7 @@ fn transDoWhileLoop(
2063) TransError!Node {2071) TransError!Node {
2064 var loop_scope = Scope{2072 var loop_scope = Scope{
2065 .parent = scope,2073 .parent = scope,
2066 .id = .loop,2074 .id = .do_loop,
2067 };2075 };
20682076
2069 // if (!cond) break;2077 // if (!cond) break;
...@@ -2075,7 +2083,14 @@ fn transDoWhileLoop(...@@ -2075,7 +2083,14 @@ fn transDoWhileLoop(
2075 };2083 };
2076 defer cond_scope.deinit();2084 defer cond_scope.deinit();
2077 const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used);2085 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
2080 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {2095 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
2081 // there's already a block in C, so we'll append our condition to it.2096 // 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 {...@@ -4099,7 +4114,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
4099 const br = blk_last.castTag(.break_val).?;4114 const br = blk_last.castTag(.break_val).?;
4100 break :blk br.data.val;4115 break :blk br.data.val;
4101 } else expr;4116 } 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|
4103 some.data.lhs4118 some.data.lhs
4104 else4119 else
4105 try Tag.typeof.create(c.arena, typeof_arg);4120 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 {...@@ -848,8 +848,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
848 break :blk try c.addIdentifier(some);848 break :blk try c.addIdentifier(some);
849 } else 0;849 } else 0;
850 return c.addNode(.{850 return c.addNode(.{
851 .tag = .identifier,851 .tag = .@"break",
852 .main_token = try c.addToken(.keyword_break, "break"),852 .main_token = tok,
853 .data = .{853 .data = .{
854 .lhs = break_label,854 .lhs = break_label,
855 .rhs = 0,855 .rhs = 0,
...@@ -864,8 +864,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -864,8 +864,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
864 break :blk try c.addIdentifier(some);864 break :blk try c.addIdentifier(some);
865 } else 0;865 } else 0;
866 return c.addNode(.{866 return c.addNode(.{
867 .tag = .identifier,867 .tag = .@"break",
868 .main_token = try c.addToken(.keyword_break, "break"),868 .main_token = tok,
869 .data = .{869 .data = .{
870 .lhs = break_label,870 .lhs = break_label,
871 .rhs = try renderNode(c, payload.val),871 .rhs = try renderNode(c, payload.val),
...@@ -1183,7 +1183,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1183,7 +1183,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1183 const l_brace = try c.addToken(.l_brace, "{");1183 const l_brace = try c.addToken(.l_brace, "{");
11841184
1185 const stmt = try renderNode(c, payload);1185 const stmt = try renderNode(c, payload);
1186 _ = try c.addToken(.semicolon, ";");1186 try addSemicolonIfNeeded(c, payload);
11871187
1188 _ = try c.addToken(.r_brace, "}");1188 _ = try c.addToken(.r_brace, "}");
1189 return c.addNode(.{1189 return c.addNode(.{
...@@ -1207,11 +1207,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1207,11 +1207,8 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1207 defer stmts.deinit();1207 defer stmts.deinit();
1208 for (payload.stmts) |stmt| {1208 for (payload.stmts) |stmt| {
1209 const res = try renderNode(c, stmt);1209 const res = try renderNode(c, stmt);
1210 switch (stmt.tag()) {1210 if (res == 0) continue;
1211 .warning => continue,1211 try addSemicolonIfNeeded(c, stmt);
1212 .var_decl, .var_simple => {},
1213 else => _ = try c.addToken(.semicolon, ";"),
1214 }
1215 try stmts.append(res);1212 try stmts.append(res);
1216 }1213 }
1217 const span = try c.listToSpan(stmts.items);1214 const span = try c.listToSpan(stmts.items);
...@@ -1245,6 +1242,194 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1245,6 +1242,194 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1245 },1242 },
1246 });1243 });
1247 },1244 },
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 },
1248 else => return c.addNode(.{1433 else => return c.addNode(.{
1249 .tag = .identifier,1434 .tag = .identifier,
1250 .main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}),1435 .main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}),
...@@ -1256,6 +1441,28 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1256,6 +1441,28 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1256 }1441 }
1257}1442}
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
1259fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {1466fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
1260 switch (node.tag()) {1467 switch (node.tag()) {
1261 .null_literal,1468 .null_literal,
...@@ -1303,19 +1510,19 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -1303,19 +1510,19 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
1303 .optional_type,1510 .optional_type,
1304 .c_pointer,1511 .c_pointer,
1305 .single_pointer,1512 .single_pointer,
1513 .unwrap,
1514 .deref,
1515 .address_of,
1516 .not,
1517 .negate,
1518 .negate_wrap,
1519 .bit_not,
1306 => {1520 => {
1307 // no grouping needed1521 // no grouping needed
1308 return renderNode(c, node);1522 return renderNode(c, node);
1309 },1523 },
13101524
1311 .negate,
1312 .negate_wrap,
1313 .bit_not,
1314 .opaque_literal,1525 .opaque_literal,
1315 .not,
1316 .address_of,
1317 .unwrap,
1318 .deref,
1319 .empty_array,1526 .empty_array,
1320 .block_single,1527 .block_single,
1321 .bool_to_int,1528 .bool_to_int,
...@@ -1407,13 +1614,11 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -1407,13 +1614,11 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
14071614
1408fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {1615fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
1409 const payload = @fieldParentPtr(Payload.UnOp, "base", node.ptr_otherwise).data;1616 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);
1412 return c.addNode(.{1617 return c.addNode(.{
1413 .tag = tag,1618 .tag = tag,
1414 .main_token = tok,1619 .main_token = try c.addToken(tok_tag, bytes),
1415 .data = .{1620 .data = .{
1416 .lhs = operand,1621 .lhs = try renderNodeGrouped(c, payload),
1417 .rhs = undefined,1622 .rhs = undefined,
1418 },1623 },
1419 });1624 });
...@@ -1508,7 +1713,7 @@ fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex {...@@ -1508,7 +1713,7 @@ fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex {
1508 .main_token = lparen,1713 .main_token = lparen,
1509 .data = .{1714 .data = .{
1510 .lhs = lhs,1715 .lhs = lhs,
1511 .rhs = try c.addExtra(std.zig.ast.Node.SubRange{1716 .rhs = try c.addExtra(NodeSubRange{
1512 .start = span.start,1717 .start = span.start,
1513 .end = span.end,1718 .end = span.end,
1514 }),1719 }),
...@@ -1728,7 +1933,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {...@@ -1728,7 +1933,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
1728 .tag = .fn_proto_multi,1933 .tag = .fn_proto_multi,
1729 .main_token = fn_token,1934 .main_token = fn_token,
1730 .data = .{1935 .data = .{
1731 .lhs = try c.addExtra(std.zig.ast.Node.SubRange{1936 .lhs = try c.addExtra(NodeSubRange{
1732 .start = span.start,1937 .start = span.start,
1733 .end = span.end,1938 .end = span.end,
1734 }),1939 }),