diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2019-10-25 14:19:56 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-25 14:19:56 -0700 |
| commit | c886ca811975e91cedca898a561ff65a5663272d (patch) | |
| tree | 43dbae0f34972f293144dde9edaadef413462508 /source/slang/slang-check-stmt.cpp | |
| parent | 7cf9b65c3836cdc17e6761bfd76383564ff0ec9d (diff) | |
Refactor semantic checking code into more files (#1097)
The semantic checking logic was all inside `slang-check.cpp` and as a result this was a monster file that was extremely hard to follow. This change splits `slang-check.cpp` into several smaller files, although some of the resulting files are still quite large.
This change attempts to be a copy-paste job as much as possible and does *not* perform any cleanup on naming, structure, duplication, etc. in the code it deal with. No function bodies or signatures have been touched.
Diffstat (limited to 'source/slang/slang-check-stmt.cpp')
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp new file mode 100644 index 000000000..5e9676a23 --- /dev/null +++ b/source/slang/slang-check-stmt.cpp @@ -0,0 +1,273 @@ +// slang-check-stmt.cpp +#include "slang-check-impl.h" + +// This file implements semantic checking logic related to statements. + +namespace Slang +{ + void SemanticsVisitor::checkStmt(Stmt* stmt) + { + if (!stmt) return; + dispatchStmt(stmt); + checkModifiers(stmt); + } + + void SemanticsVisitor::visitDeclStmt(DeclStmt* stmt) + { + // We directly dispatch here instead of using `EnsureDecl()` for two + // reasons: + // + // 1. We expect that a local declaration won't have been referenced + // before it is declared, so that we can just check things in-order + // + // 2. `EnsureDecl()` is specialized for `Decl*` instead of `DeclBase*` + // and trying to special case `DeclGroup*` here feels silly. + // + dispatchDecl(stmt->decl); + checkModifiers(stmt->decl); + } + + void SemanticsVisitor::visitBlockStmt(BlockStmt* stmt) + { + checkStmt(stmt->body); + } + + void SemanticsVisitor::visitSeqStmt(SeqStmt* stmt) + { + for(auto ss : stmt->stmts) + { + checkStmt(ss); + } + } + + template<typename T> + T* SemanticsVisitor::FindOuterStmt() + { + const Index outerStmtCount = outerStmts.getCount(); + for (Index ii = outerStmtCount; ii > 0; --ii) + { + auto outerStmt = outerStmts[ii-1]; + auto found = as<T>(outerStmt); + if (found) + return found; + } + return nullptr; + } + + void SemanticsVisitor::visitBreakStmt(BreakStmt *stmt) + { + auto outer = FindOuterStmt<BreakableStmt>(); + if (!outer) + { + getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop); + } + stmt->parentStmt = outer; + } + + void SemanticsVisitor::visitContinueStmt(ContinueStmt *stmt) + { + auto outer = FindOuterStmt<LoopStmt>(); + if (!outer) + { + getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop); + } + stmt->parentStmt = outer; + } + + void SemanticsVisitor::PushOuterStmt(Stmt* stmt) + { + outerStmts.add(stmt); + } + + void SemanticsVisitor::PopOuterStmt(Stmt* /*stmt*/) + { + outerStmts.removeAt(outerStmts.getCount() - 1); + } + + RefPtr<Expr> SemanticsVisitor::checkPredicateExpr(Expr* expr) + { + RefPtr<Expr> e = expr; + e = CheckTerm(e); + e = coerce(getSession()->getBoolType(), e); + return e; + } + + void SemanticsVisitor::visitDoWhileStmt(DoWhileStmt *stmt) + { + PushOuterStmt(stmt); + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->Statement); + + PopOuterStmt(stmt); + } + + void SemanticsVisitor::visitForStmt(ForStmt *stmt) + { + PushOuterStmt(stmt); + checkStmt(stmt->InitialStatement); + if (stmt->PredicateExpression) + { + stmt->PredicateExpression = checkPredicateExpr(stmt->PredicateExpression); + } + if (stmt->SideEffectExpression) + { + stmt->SideEffectExpression = CheckExpr(stmt->SideEffectExpression); + } + checkStmt(stmt->Statement); + + PopOuterStmt(stmt); + } + + RefPtr<Expr> SemanticsVisitor::checkExpressionAndExpectIntegerConstant(RefPtr<Expr> expr, RefPtr<IntVal>* outIntVal) + { + expr = CheckExpr(expr); + auto intVal = CheckIntegerConstantExpression(expr); + if (outIntVal) + *outIntVal = intVal; + return expr; + } + + void SemanticsVisitor::visitCompileTimeForStmt(CompileTimeForStmt* stmt) + { + PushOuterStmt(stmt); + + stmt->varDecl->type.type = getSession()->getIntType(); + addModifier(stmt->varDecl, new ConstModifier()); + stmt->varDecl->SetCheckState(DeclCheckState::Checked); + + RefPtr<IntVal> rangeBeginVal; + RefPtr<IntVal> rangeEndVal; + + if (stmt->rangeBeginExpr) + { + stmt->rangeBeginExpr = checkExpressionAndExpectIntegerConstant(stmt->rangeBeginExpr, &rangeBeginVal); + } + else + { + RefPtr<ConstantIntVal> rangeBeginConst = new ConstantIntVal(); + rangeBeginConst->value = 0; + rangeBeginVal = rangeBeginConst; + } + + stmt->rangeEndExpr = checkExpressionAndExpectIntegerConstant(stmt->rangeEndExpr, &rangeEndVal); + + stmt->rangeBeginVal = rangeBeginVal; + stmt->rangeEndVal = rangeEndVal; + + checkStmt(stmt->body); + + + PopOuterStmt(stmt); + } + + void SemanticsVisitor::visitSwitchStmt(SwitchStmt* stmt) + { + PushOuterStmt(stmt); + // TODO(tfoley): need to coerce condition to an integral type... + stmt->condition = CheckExpr(stmt->condition); + checkStmt(stmt->body); + + // TODO(tfoley): need to check that all case tags are unique + + // TODO(tfoley): check that there is at most one `default` clause + + PopOuterStmt(stmt); + } + + void SemanticsVisitor::visitCaseStmt(CaseStmt* stmt) + { + // TODO(tfoley): Need to coerce to type being switch on, + // and ensure that value is a compile-time constant + auto expr = CheckExpr(stmt->expr); + auto switchStmt = FindOuterStmt<SwitchStmt>(); + + if (!switchStmt) + { + getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); + } + else + { + // TODO: need to do some basic matching to ensure the type + // for the `case` is consistent with the type for the `switch`... + } + + stmt->expr = expr; + stmt->parentStmt = switchStmt; + } + + void SemanticsVisitor::visitDefaultStmt(DefaultStmt* stmt) + { + auto switchStmt = FindOuterStmt<SwitchStmt>(); + if (!switchStmt) + { + getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); + } + stmt->parentStmt = switchStmt; + } + + void SemanticsVisitor::visitIfStmt(IfStmt *stmt) + { + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->PositiveStatement); + checkStmt(stmt->NegativeStatement); + } + + void SemanticsVisitor::visitUnparsedStmt(UnparsedStmt*) + { + // Nothing to do + } + + void SemanticsVisitor::visitEmptyStmt(EmptyStmt*) + { + // Nothing to do + } + + void SemanticsVisitor::visitDiscardStmt(DiscardStmt*) + { + // Nothing to do + } + + void SemanticsVisitor::visitReturnStmt(ReturnStmt *stmt) + { + if (!stmt->Expression) + { + if (function && !function->ReturnType.Equals(getSession()->getVoidType())) + { + getSink()->diagnose(stmt, Diagnostics::returnNeedsExpression); + } + } + else + { + stmt->Expression = CheckTerm(stmt->Expression); + if (!stmt->Expression->type->Equals(getSession()->getErrorType())) + { + if (function) + { + stmt->Expression = coerce(function->ReturnType.Ptr(), stmt->Expression); + } + else + { + // TODO(tfoley): this case currently gets triggered for member functions, + // which aren't being checked consistently (because of the whole symbol + // table idea getting in the way). + +// getSink()->diagnose(stmt, Diagnostics::unimplemented, "case for return stmt"); + } + } + } + } + + void SemanticsVisitor::visitWhileStmt(WhileStmt *stmt) + { + PushOuterStmt(stmt); + stmt->Predicate = checkPredicateExpr(stmt->Predicate); + checkStmt(stmt->Statement); + PopOuterStmt(stmt); + } + + void SemanticsVisitor::visitExpressionStmt(ExpressionStmt *stmt) + { + stmt->Expression = CheckExpr(stmt->Expression); + } + +} |
