| ... | ... | @@ -54,6 +54,7 @@ const Scope = struct { |
| 54 | 54 | |
| 55 | 55 | const Switch = struct { |
| 56 | 56 | base: Scope, |
| 57 | label: []const u8, |
| 57 | 58 | }; |
| 58 | 59 | |
| 59 | 60 | /// used when getting a member `a.b` |
| ... | ... | @@ -190,6 +191,7 @@ const Scope = struct { |
| 190 | 191 | .Ref => null, |
| 191 | 192 | .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), |
| 192 | 193 | .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), |
| 194 | .Condition => scope.parent.?.getAlias(name), |
| 193 | 195 | else => @panic("TODO Scope.getAlias"), |
| 194 | 196 | }; |
| 195 | 197 | } |
| ... | ... | @@ -200,9 +202,15 @@ const Scope = struct { |
| 200 | 202 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), |
| 201 | 203 | .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), |
| 202 | 204 | .Block => @fieldParentPtr(Block, "base", scope).contains(name), |
| 205 | .Condition => scope.parent.?.contains(name), |
| 203 | 206 | else => @panic("TODO Scope.contains"), |
| 204 | 207 | }; |
| 205 | 208 | } |
| 209 | |
| 210 | fn getBreakableScope(scope: *Scope) *Scope { |
| 211 | var scope = inner; |
| 212 | while (scope.id != .Switch and scope.id != .Root) : (scope = scope.parent.?) {} |
| 213 | } |
| 206 | 214 | }; |
| 207 | 215 | |
| 208 | 216 | const Context = struct { |
| ... | ... | @@ -613,6 +621,13 @@ fn transStmt( |
| 613 | 621 | .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)), |
| 614 | 622 | .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), |
| 615 | 623 | .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), |
| 624 | .NullStmtClass => { |
| 625 | const block = try transCreateNodeBlock(rp.c, null); |
| 626 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 627 | return &block.base; |
| 628 | }, |
| 629 | .ContinueStmtClass => return transCreateNodeContinue(rp.c), |
| 630 | .BreakStmtClass => return transBreak(rp, scope), |
| 616 | 631 | else => { |
| 617 | 632 | return revertAndWarn( |
| 618 | 633 | rp, |
| ... | ... | @@ -1241,7 +1256,7 @@ fn transDoWhileLoop( |
| 1241 | 1256 | _ = try appendToken(rp.c, .RParen, ")"); |
| 1242 | 1257 | var new = false; |
| 1243 | 1258 | |
| 1244 | | const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) |
| 1259 | const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: { |
| 1245 | 1260 | // there's already a block in C, so we'll append our condition to it. |
| 1246 | 1261 | // c: do { |
| 1247 | 1262 | // c: a; |
| ... | ... | @@ -1252,8 +1267,8 @@ fn transDoWhileLoop( |
| 1252 | 1267 | // zig: b; |
| 1253 | 1268 | // zig: if (!cond) break; |
| 1254 | 1269 | // zig: } |
| 1255 | | (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).? |
| 1256 | | else blk: { |
| 1270 | break :blk (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).? |
| 1271 | } else blk: { |
| 1257 | 1272 | // the C statement is without a block, so we need to create a block to contain it. |
| 1258 | 1273 | // c: do |
| 1259 | 1274 | // c: a; |
| ... | ... | @@ -1262,7 +1277,6 @@ fn transDoWhileLoop( |
| 1262 | 1277 | // zig: a; |
| 1263 | 1278 | // zig: if (!cond) break; |
| 1264 | 1279 | // zig: } |
| 1265 | | |
| 1266 | 1280 | new = true; |
| 1267 | 1281 | const block = try transCreateNodeBlock(rp.c, null); |
| 1268 | 1282 | try block.statements.push(try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); |
| ... | ... | @@ -1328,6 +1342,15 @@ fn transCPtrCast( |
| 1328 | 1342 | return &ptrcast_node.base; |
| 1329 | 1343 | } |
| 1330 | 1344 | |
| 1345 | fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { |
| 1346 | const break_scope = scope.getBreakableScope(); |
| 1347 | const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch) |
| 1348 | @fieldParentPtr(Scope.Switch, "base", break_scope).label |
| 1349 | else |
| 1350 | null); |
| 1351 | return &br.base; |
| 1352 | } |
| 1353 | |
| 1331 | 1354 | fn maybeSuppressResult( |
| 1332 | 1355 | rp: RestorePoint, |
| 1333 | 1356 | scope: *Scope, |
| ... | ... | @@ -2165,6 +2188,18 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While { |
| 2165 | 2188 | return node; |
| 2166 | 2189 | } |
| 2167 | 2190 | |
| 2191 | fn transCreateNodeContinue(c: *Context) !*ast.Node { |
| 2192 | const ltoken = try appendToken(c, .Keyword_continue, "continue"); |
| 2193 | const node = try c.a().create(ast.Node.ControlFlowExpression); |
| 2194 | node.* = .{ |
| 2195 | .ltoken = ltoken, |
| 2196 | .kind = .{ .Continue = null }, |
| 2197 | .rhs = null, |
| 2198 | }; |
| 2199 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2200 | return &node.base; |
| 2201 | } |
| 2202 | |
| 2168 | 2203 | const RestorePoint = struct { |
| 2169 | 2204 | c: *Context, |
| 2170 | 2205 | token_index: ast.TokenIndex, |