| 13 | } |
| 14 | |
| 15 | bool GcnTokenListVerifier::verify(const GcnTokenList& tokens) const |
| 16 | { |
| 17 | std::vector<const GcnToken*> scopeStack; |
| 18 | std::unordered_set<const GcnToken*> activeScopes; |
| 19 | |
| 20 | for (const GcnToken* token : tokens) |
| 21 | { |
| 22 | switch (token->kind()) |
| 23 | { |
| 24 | case GcnTokenKind::Code: |
| 25 | break; |
| 26 | case GcnTokenKind::Loop: |
| 27 | case GcnTokenKind::Block: |
| 28 | case GcnTokenKind::If: |
| 29 | case GcnTokenKind::IfNot: |
| 30 | { |
| 31 | scopeStack.push_back(token); |
| 32 | activeScopes.insert(token); |
| 33 | } |
| 34 | break; |
| 35 | case GcnTokenKind::Else: |
| 36 | { |
| 37 | if (scopeStack.empty()) |
| 38 | { |
| 39 | LOG_ERR("Scope stack empty but ELSE Token found"); |
| 40 | return false; |
| 41 | } |
| 42 | if (token->getMatch()->kind() != GcnTokenKind::End) |
| 43 | { |
| 44 | LOG_ERR("Match for ELSE Token is not a END Token"); |
| 45 | return false; |
| 46 | } |
| 47 | if (token->getMatch()->getMatch()->kind() != GcnTokenKind::If) |
| 48 | { |
| 49 | LOG_ERR("Match for END after ELSE Token is not a IF Token"); |
| 50 | return false; |
| 51 | } |
| 52 | const GcnToken* match = scopeStack.back(); |
| 53 | if (match->getMatch() != token) |
| 54 | { |
| 55 | LOG_ERR("ELSE Token is not the match of the current Token in the stack"); |
| 56 | return false; |
| 57 | } |
| 58 | break; |
| 59 | } |
| 60 | case GcnTokenKind::End: |
| 61 | { |
| 62 | if (scopeStack.empty()) |
| 63 | { |
| 64 | LOG_ERR("Scope stack empty but END Token found"); |
| 65 | return false; |
| 66 | } |
| 67 | const GcnToken* match = scopeStack.back(); |
| 68 | if (match != token->getMatch()) |
| 69 | { |
| 70 | LOG_ERR("Top Token in the stack is not the match for current END Token:"); |
| 71 | LOG_ERR("Current: %s", token->dump().c_str()); |
| 72 | LOG_ERR("Top: %s", match->dump().c_str()); |