diff options
Diffstat (limited to 'source/slang/slang-check-stmt.cpp')
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 122 |
1 files changed, 94 insertions, 28 deletions
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp index c85eb7593..8a914c60b 100644 --- a/source/slang/slang-check-stmt.cpp +++ b/source/slang/slang-check-stmt.cpp @@ -149,60 +149,102 @@ Stmt* SemanticsStmtVisitor::findOuterStmtWithLabel(Name* label) return nullptr; } +void SemanticsStmtVisitor::generateUniqueIDForStmt(BreakableStmt* stmt) +{ + stmt->uniqueID = getASTBuilder()->generateUniqueIDForStmt(); +} + void SemanticsStmtVisitor::visitBreakStmt(BreakStmt* stmt) { - Stmt* targetStmt = nullptr; + // We need to identify the enclosing statement that + // this `break` is meant to break out of. + // + BreakableStmt* targetOuterStmt = nullptr; if (stmt->targetLabel.type == TokenType::Identifier) { - // This is a break statement with an explicit target label. - // Try to find the outer stmt with the label. - targetStmt = findOuterStmtWithLabel(stmt->targetLabel.getName()); - if (!targetStmt) + // If this is a `break` statement that specifies + // an explicit label, then we will search for + // an outer statement matching that label. + // + auto foundOuterStmt = findOuterStmtWithLabel(stmt->targetLabel.getName()); + if (!foundOuterStmt) { getSink()->diagnose(stmt, Diagnostics::breakLabelNotFound, stmt->targetLabel.getName()); } - if (!as<BreakableStmt>(targetStmt)) + else { - getSink()->diagnose( - stmt, - Diagnostics::targetLabelDoesNotMarkBreakableStmt, - stmt->targetLabel.getName()); + // It is possible that the labelled statement + // is not a valid one for a `break` to target, + // so we check for that next. + // + targetOuterStmt = as<BreakableStmt>(foundOuterStmt); + if (!targetOuterStmt) + { + getSink()->diagnose( + stmt, + Diagnostics::targetLabelDoesNotMarkBreakableStmt, + stmt->targetLabel.getName()); + } } } else { - // For `break` statements without an explicit target, - // find the inner most breakable stmt. - targetStmt = FindOuterStmt<BreakableStmt>(); - if (!targetStmt) + // If there is no explicit label on the `break` statement, + // then we are simply searching for the inner-most + // enclosing statement that is a valid `break` target. + // + targetOuterStmt = FindOuterStmt<BreakableStmt>(); + if (!targetOuterStmt) { getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop); } } - // If there is a defer statement before the breakable statement, it's - // illegal. - if (FindOuterStmt<DeferStmt>(targetStmt)) + // We do not (currently) allow a `break` to proceed "through" + // an enclosing `defer` statement. Thus, we search for + // a possible enclosing `defer` statement, between the + // `stmt` being checked and the `targetOuterStmt` that + // `stmt` is trying to branch to. + // + // TODO: This is a reasonable feature to add down the line; + // it simply involves more implementation complexity than + // the simpler cases of `defer`. + // + if (targetOuterStmt) { - getSink()->diagnose(stmt, Diagnostics::breakInsideDefer); - } + if (FindOuterStmt<DeferStmt>(targetOuterStmt)) + { + getSink()->diagnose(stmt, Diagnostics::breakInsideDefer); + } - stmt->parentStmt = targetStmt; + // We stash the ID of the target statement in the `break` + // statement so that they can be correlated later, during + // code generation. + // + stmt->targetOuterStmtID = targetOuterStmt->uniqueID; + } } void SemanticsStmtVisitor::visitContinueStmt(ContinueStmt* stmt) { - auto outer = FindOuterStmt<LoopStmt>(); - if (!outer) + auto targetOuterStmt = FindOuterStmt<LoopStmt>(); + if (!targetOuterStmt) { getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop); } - - if (FindOuterStmt<DeferStmt>(outer)) + else { - getSink()->diagnose(stmt, Diagnostics::continueInsideDefer); + if (FindOuterStmt<DeferStmt>(targetOuterStmt)) + { + getSink()->diagnose(stmt, Diagnostics::continueInsideDefer); + } + + // We stash the ID of the target statement in the `continue` + // statement so that they can be correlated later, during + // code generation. + // + stmt->targetOuterStmtID = targetOuterStmt->uniqueID; } - stmt->parentStmt = outer; } Expr* SemanticsVisitor::checkPredicateExpr(Expr* expr) @@ -219,6 +261,7 @@ Expr* SemanticsVisitor::checkPredicateExpr(Expr* expr) void SemanticsStmtVisitor::visitDoWhileStmt(DoWhileStmt* stmt) { + generateUniqueIDForStmt(stmt); checkModifiers(stmt); WithOuterStmt subContext(this, stmt); @@ -229,6 +272,7 @@ void SemanticsStmtVisitor::visitDoWhileStmt(DoWhileStmt* stmt) void SemanticsStmtVisitor::visitForStmt(ForStmt* stmt) { + generateUniqueIDForStmt(stmt); WithOuterStmt subContext(this, stmt); checkModifiers(stmt); checkStmt(stmt->initialStatement); @@ -342,6 +386,7 @@ void SemanticsStmtVisitor::validateCaseStmts(SwitchStmt* stmt, DiagnosticSink* s void SemanticsStmtVisitor::visitSwitchStmt(SwitchStmt* stmt) { + generateUniqueIDForStmt(stmt); WithOuterStmt subContext(this, stmt); // TODO(tfoley): need to coerce condition to an integral type... @@ -372,11 +417,20 @@ void SemanticsStmtVisitor::visitCaseStmt(CaseStmt* stmt) stmt->expr = expr; stmt->exprVal = exprVal; - stmt->parentStmt = switchStmt; + + if (switchStmt) + { + // We stash the ID of the target statement in the `case` + // statement so that they can be correlated later, during + // code generation. + // + stmt->targetOuterStmtID = switchStmt->uniqueID; + } } void SemanticsStmtVisitor::visitTargetSwitchStmt(TargetSwitchStmt* stmt) { + generateUniqueIDForStmt(stmt); WithOuterStmt subContext(this, stmt); HashSet<Stmt*> checkedStmt; for (auto caseStmt : stmt->targetCases) @@ -436,6 +490,10 @@ void SemanticsStmtVisitor::visitTargetCaseStmt(TargetCaseStmt* stmt) { getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); } + else + { + stmt->targetOuterStmtID = switchStmt->uniqueID; + } WithOuterStmt subContext(this, stmt); subContext.checkStmt(stmt->body); } @@ -454,7 +512,14 @@ void SemanticsStmtVisitor::visitDefaultStmt(DefaultStmt* stmt) { getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); } - stmt->parentStmt = switchStmt; + else + { + // We stash the ID of the target statement in the `case` + // statement so that they can be correlated later, during + // code generation. + // + stmt->targetOuterStmtID = switchStmt->uniqueID; + } } void SemanticsStmtVisitor::visitIfStmt(IfStmt* stmt) @@ -520,6 +585,7 @@ void SemanticsStmtVisitor::visitReturnStmt(ReturnStmt* stmt) void SemanticsStmtVisitor::visitWhileStmt(WhileStmt* stmt) { + generateUniqueIDForStmt(stmt); checkModifiers(stmt); WithOuterStmt subContext(this, stmt); stmt->predicate = checkPredicateExpr(stmt->predicate); |
