src/ast/ASTNodes.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include <ast/ASTNodes.h> | ||
| 4 | |||
| 5 | #include <ANTLRInputStream.h> | ||
| 6 | |||
| 7 | #include <SourceFile.h> | ||
| 8 | #include <ast/Attributes.h> | ||
| 9 | #include <exception/SemanticError.h> | ||
| 10 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
| 11 | #include <typechecker/BuiltinFunctions.h> | ||
| 12 | |||
| 13 | namespace spice::compiler { | ||
| 14 | |||
| 15 | // Constant definitions | ||
| 16 | static constexpr size_t ERROR_MESSAGE_CONTEXT = 20; | ||
| 17 | |||
| 18 | 5683 | std::string ASTNode::getErrorMessage() const { | |
| 19 | 5683 | antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get(); | |
| 20 | 5683 | const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval; | |
| 21 | 5683 | antlr4::misc::Interval extSourceInterval(sourceInterval); | |
| 22 | |||
| 23 | // If we have a multi-line interval, only use the first line | ||
| 24 |
3/4✓ Branch 3 → 4 taken 5683 times.
✗ Branch 3 → 77 not taken.
✓ Branch 6 → 7 taken 38 times.
✓ Branch 6 → 8 taken 5645 times.
|
5683 | if (const size_t offset = inputStream->getText(extSourceInterval).find('\n'); offset != std::string::npos) |
| 25 | 38 | extSourceInterval.b = extSourceInterval.a + static_cast<ssize_t>(offset); | |
| 26 | |||
| 27 | 5683 | size_t markerIndentation = 0; | |
| 28 |
2/2✓ Branch 20 → 9 taken 68284 times.
✓ Branch 20 → 21 taken 1779 times.
|
70063 | for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) { |
| 29 | 68284 | extSourceInterval.a--; | |
| 30 |
9/12✓ Branch 9 → 10 taken 68252 times.
✓ Branch 9 → 13 taken 32 times.
✓ Branch 10 → 11 taken 68252 times.
✗ Branch 10 → 78 not taken.
✓ Branch 12 → 13 taken 3872 times.
✓ Branch 12 → 14 taken 64380 times.
✓ Branch 15 → 16 taken 68252 times.
✓ Branch 15 → 17 taken 32 times.
✓ Branch 17 → 18 taken 3904 times.
✓ Branch 17 → 19 taken 64380 times.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
|
68284 | if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
| 31 | 3904 | extSourceInterval.a++; | |
| 32 | 3904 | break; | |
| 33 | } | ||
| 34 | } | ||
| 35 |
2/2✓ Branch 34 → 22 taken 17970 times.
✓ Branch 34 → 35 taken 120 times.
|
18090 | for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) { |
| 36 | 17970 | extSourceInterval.b++; | |
| 37 |
4/6✓ Branch 22 → 23 taken 17970 times.
✗ Branch 22 → 82 not taken.
✓ Branch 23 → 24 taken 17970 times.
✗ Branch 23 → 27 not taken.
✓ Branch 26 → 27 taken 5563 times.
✓ Branch 26 → 28 taken 12407 times.
|
35940 | if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() || |
| 38 |
4/8✓ Branch 24 → 25 taken 17970 times.
✗ Branch 24 → 82 not taken.
✓ Branch 29 → 30 taken 17970 times.
✗ Branch 29 → 31 not taken.
✓ Branch 31 → 32 taken 5563 times.
✓ Branch 31 → 33 taken 12407 times.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
35940 | inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
| 39 | 5563 | extSourceInterval.b--; | |
| 40 | 5563 | break; | |
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | // Trim start | ||
| 45 |
3/4✓ Branch 37 → 38 taken 33962 times.
✗ Branch 37 → 86 not taken.
✓ Branch 40 → 36 taken 28279 times.
✓ Branch 40 → 41 taken 5683 times.
|
33962 | while (inputStream->getText(extSourceInterval)[0] == ' ') { |
| 46 | 28279 | extSourceInterval.a++; | |
| 47 | 28279 | markerIndentation--; | |
| 48 | } | ||
| 49 | |||
| 50 | // Trim end | ||
| 51 |
3/4✓ Branch 41 → 42 taken 5683 times.
✗ Branch 41 → 87 not taken.
✓ Branch 45 → 46 taken 38 times.
✓ Branch 45 → 47 taken 5645 times.
|
5683 | if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n') |
| 52 | 38 | extSourceInterval.b--; | |
| 53 | |||
| 54 | 5683 | const std::string lineNumberStr = std::to_string(codeLoc.line); | |
| 55 | 5683 | markerIndentation += lineNumberStr.length() + 2; | |
| 56 | |||
| 57 | // Build error message | ||
| 58 |
1/2✓ Branch 49 → 50 taken 5683 times.
✗ Branch 49 → 107 not taken.
|
5683 | std::stringstream ss; |
| 59 |
5/10✓ Branch 50 → 51 taken 5683 times.
✗ Branch 50 → 105 not taken.
✓ Branch 51 → 52 taken 5683 times.
✗ Branch 51 → 105 not taken.
✓ Branch 52 → 53 taken 5683 times.
✗ Branch 52 → 90 not taken.
✓ Branch 53 → 54 taken 5683 times.
✗ Branch 53 → 88 not taken.
✓ Branch 54 → 55 taken 5683 times.
✗ Branch 54 → 88 not taken.
|
5683 | ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n"; |
| 60 |
2/4✓ Branch 58 → 59 taken 5683 times.
✗ Branch 58 → 93 not taken.
✓ Branch 59 → 60 taken 5683 times.
✗ Branch 59 → 91 not taken.
|
11366 | ss << std::string(markerIndentation, ' '); |
| 61 |
2/4✓ Branch 67 → 68 taken 5683 times.
✗ Branch 67 → 99 not taken.
✓ Branch 68 → 69 taken 5683 times.
✗ Branch 68 → 97 not taken.
|
5683 | ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^'); |
| 62 |
1/2✓ Branch 71 → 72 taken 5683 times.
✗ Branch 71 → 105 not taken.
|
11366 | return ss.str(); |
| 63 | 5683 | } | |
| 64 | |||
| 65 | 271589 | const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion) | |
| 66 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 271589 times.
|
271589 | assert(parent != nullptr); |
| 67 |
2/2✓ Branch 5 → 6 taken 126974 times.
✓ Branch 5 → 16 taken 144615 times.
|
398563 | return isStmtLst() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst(); |
| 68 | } | ||
| 69 | |||
| 70 | 96 | std::string ASTNode::getEnclosingFunctionSignature(size_t manIdx) const { // NOLINT(*-no-recursion) | |
| 71 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 96 times.
|
96 | assert(parent != nullptr); |
| 72 |
2/2✓ Branch 5 → 6 taken 16 times.
✓ Branch 5 → 7 taken 80 times.
|
96 | return isFctOrProcDef() ? getFunctionSignature(manIdx) : parent->getEnclosingFunctionSignature(manIdx); |
| 73 | } | ||
| 74 | |||
| 75 | 1208 | bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 76 | 1208 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 77 | } | ||
| 78 | |||
| 79 | 80548 | bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 80 | 80548 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 81 | } | ||
| 82 | |||
| 83 | 887 | CompileTimeValue GlobalVarDefNode::getCompileTimeValue(size_t manIdx) const { return constant->getCompileTimeValue(manIdx); } | |
| 84 | |||
| 85 | 5811 | bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 86 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
| 87 | // we can assume that the loop itself will always return | ||
| 88 |
3/4✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 7 taken 5809 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
|
5811 | const bool condAlwaysTrue = condAssign->hasCompileTimeValue(manIdx) && condAssign->getCompileTimeValue(manIdx).boolValue; |
| 89 |
1/4✗ Branch 8 → 9 not taken.
✓ Branch 8 → 12 taken 5811 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
5811 | return condAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); |
| 90 | } | ||
| 91 | |||
| 92 | 2997 | bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 93 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
| 94 | // we can assume that the loop itself will always return | ||
| 95 |
3/4✓ Branch 3 → 4 taken 116 times.
✓ Branch 3 → 7 taken 2881 times.
✓ Branch 5 → 6 taken 116 times.
✗ Branch 5 → 7 not taken.
|
2997 | const bool condAlwaysTrue = condition->hasCompileTimeValue(manIdx) && condition->getCompileTimeValue(manIdx).boolValue; |
| 96 |
4/4✓ Branch 8 → 9 taken 116 times.
✓ Branch 8 → 12 taken 2881 times.
✓ Branch 10 → 11 taken 18 times.
✓ Branch 10 → 12 taken 98 times.
|
2997 | return condAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); |
| 97 | } | ||
| 98 | |||
| 99 | 37 | bool DoWhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 100 | // Do-while loops will always be executed at least once. So if the body returns on all control paths, the loop will as well | ||
| 101 | 37 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 102 | } | ||
| 103 | |||
| 104 | 32836 | bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { // NOLINT(misc-no-recursion) | |
| 105 | // If the condition always evaluates to 'true' the then block must return | ||
| 106 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 32836 times.
|
32836 | if (!doCompileElseBranch(manIdx)) |
| 107 | ✗ | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 108 | |||
| 109 | // If the condition always evaluates to 'false' the else block must return | ||
| 110 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 14 taken 32836 times.
|
32836 | if (!doCompileThenBranch(manIdx)) |
| 111 | ✗ | return elseStmt != nullptr && elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 112 | |||
| 113 | // If the condition does not always evaluate to 'true' or 'false' we need to check both branches | ||
| 114 |
4/4✓ Branch 15 → 16 taken 23864 times.
✓ Branch 15 → 20 taken 8972 times.
✓ Branch 16 → 17 taken 301 times.
✓ Branch 16 → 20 taken 23563 times.
|
33137 | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx) && elseStmt != nullptr && |
| 115 |
2/2✓ Branch 18 → 19 taken 249 times.
✓ Branch 18 → 20 taken 52 times.
|
33137 | elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); |
| 116 | } | ||
| 117 | |||
| 118 | 301 | bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, | |
| 119 | size_t manIdx) const { // NOLINT(misc-no-recursion) | ||
| 120 |
2/2✓ Branch 2 → 3 taken 110 times.
✓ Branch 2 → 5 taken 191 times.
|
301 | if (isElseIf) |
| 121 | 110 | return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 122 | 191 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 123 | } | ||
| 124 | |||
| 125 | 188 | bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 126 | 1208 | const auto pred = [=](const CaseBranchNode *node) { | |
| 127 | 1020 | return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 128 | 188 | }; | |
| 129 |
1/2✓ Branch 2 → 3 taken 188 times.
✗ Branch 2 → 14 not taken.
|
188 | const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred); |
| 130 | const bool defaultBranchReturns = | ||
| 131 |
5/6✓ Branch 3 → 4 taken 156 times.
✓ Branch 3 → 6 taken 32 times.
✓ Branch 4 → 5 taken 156 times.
✗ Branch 4 → 14 not taken.
✓ Branch 5 → 6 taken 134 times.
✓ Branch 5 → 7 taken 22 times.
|
188 | !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); |
| 132 |
3/4✓ Branch 8 → 9 taken 118 times.
✓ Branch 8 → 11 taken 70 times.
✓ Branch 9 → 10 taken 118 times.
✗ Branch 9 → 11 not taken.
|
188 | return allCaseBranchesReturn && defaultBranchReturns; |
| 133 | } | ||
| 134 | |||
| 135 | 1020 | bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 136 | 1020 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 137 | } | ||
| 138 | |||
| 139 | 156 | bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 140 | 156 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 141 | } | ||
| 142 | |||
| 143 | 132400 | bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 144 | // An empty statement list does not return at all | ||
| 145 |
2/2✓ Branch 3 → 4 taken 439 times.
✓ Branch 3 → 5 taken 131961 times.
|
132400 | if (statements.empty()) |
| 146 | 439 | return false; | |
| 147 | // A statement list returns on all control paths, if the one direct child statement returns on all control paths | ||
| 148 | 131961 | bool returnsOnAllControlPaths = false; | |
| 149 |
2/2✓ Branch 26 → 7 taken 259356 times.
✓ Branch 26 → 27 taken 131961 times.
|
523278 | for (StmtNode *child : statements) { |
| 150 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 259356 times.
|
259356 | assert(child != nullptr); |
| 151 | |||
| 152 | // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false | ||
| 153 |
4/4✓ Branch 11 → 12 taken 4812 times.
✓ Branch 11 → 14 taken 254544 times.
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 14 taken 4806 times.
|
259356 | if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable) |
| 154 | 6 | child->unreachable = true; | |
| 155 | |||
| 156 |
3/4✓ Branch 14 → 15 taken 259356 times.
✗ Branch 14 → 29 not taken.
✓ Branch 15 → 16 taken 81635 times.
✓ Branch 15 → 17 taken 177721 times.
|
259356 | if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx)) |
| 157 | 81635 | returnsOnAllControlPaths = true; | |
| 158 | } | ||
| 159 | 131961 | return returnsOnAllControlPaths; | |
| 160 | } | ||
| 161 | |||
| 162 | 14872 | std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const { | |
| 163 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14872 times.
|
14872 | assert(ATTR_CONFIGS.contains(key)); |
| 164 | |||
| 165 | 14872 | std::vector<const CompileTimeValue *> attributeValues; | |
| 166 |
2/2✓ Branch 28 → 7 taken 25528 times.
✓ Branch 28 → 29 taken 14872 times.
|
55272 | for (const AttrNode *attrNode : attributes) { |
| 167 | // Skip attributes with different keys | ||
| 168 |
2/2✓ Branch 10 → 11 taken 19160 times.
✓ Branch 10 → 12 taken 6368 times.
|
25528 | if (attrNode->key != key) |
| 169 | 19160 | continue; | |
| 170 | |||
| 171 | // Found a matching attribute | ||
| 172 | 6368 | const CompileTimeValue *value = attrNode->getValue(); | |
| 173 |
2/2✓ Branch 13 → 14 taken 514 times.
✓ Branch 13 → 16 taken 5854 times.
|
6368 | if (!value) { |
| 174 | // If the attribute has no value, we use the default value | ||
| 175 |
1/2✓ Branch 14 → 15 taken 514 times.
✗ Branch 14 → 31 not taken.
|
514 | attributeValues.push_back(&DEFAULT_BOOL_COMPILE_VALUE); |
| 176 | } else { | ||
| 177 | // If the attribute has a value, we use the value | ||
| 178 |
1/2✓ Branch 16 → 17 taken 5854 times.
✗ Branch 16 → 32 not taken.
|
5854 | attributeValues.push_back(value); |
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | 14872 | return attributeValues; | |
| 183 | ✗ | } | |
| 184 | |||
| 185 | 8134 | const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const { | |
| 186 |
1/2✓ Branch 2 → 3 taken 8134 times.
✗ Branch 2 → 12 not taken.
|
8134 | const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key); |
| 187 |
2/2✓ Branch 4 → 5 taken 4792 times.
✓ Branch 4 → 6 taken 3342 times.
|
16268 | return attrs.empty() ? nullptr : attrs.back(); |
| 188 | 8134 | } | |
| 189 | |||
| 190 | 12634 | bool AttrLstNode::hasAttr(const std::string &key) const { | |
| 191 | 38394 | return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; }); | |
| 192 | } | ||
| 193 | |||
| 194 |
2/2✓ Branch 2 → 3 taken 5854 times.
✓ Branch 2 → 4 taken 514 times.
|
6368 | const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; } |
| 195 | |||
| 196 | 42452 | bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable, size_t manIdx) const { | |
| 197 | // If it's a ternary, do the default thing | ||
| 198 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 42452 times.
|
42452 | if (op == AssignOp::OP_NONE) |
| 199 | ✗ | return ternaryExpr->returnsOnAllControlPaths(doSetPredecessorsUnreachable, manIdx); | |
| 200 | |||
| 201 | // If it's a modification on the result variable, we technically return from the function, but at the end of the function. | ||
| 202 | 42452 | const AtomicExprNode *atomicExpr = getLhsAtomicNode(); | |
| 203 |
6/6✓ Branch 6 → 7 taken 41965 times.
✓ Branch 6 → 10 taken 487 times.
✓ Branch 8 → 9 taken 4086 times.
✓ Branch 8 → 10 taken 37879 times.
✓ Branch 11 → 12 taken 4086 times.
✓ Branch 11 → 13 taken 38366 times.
|
42452 | if (atomicExpr && atomicExpr->fqIdentifier == RETURN_VARIABLE_NAME) { |
| 204 | // If we assign the result variable, we technically return from the function, but at the end of the function. | ||
| 205 | // Therefore, the following code is not unreachable, but will be executed in any case. | ||
| 206 | 4086 | *doSetPredecessorsUnreachable = false; | |
| 207 | 4086 | return true; | |
| 208 | } | ||
| 209 | |||
| 210 | 38366 | return false; | |
| 211 | } | ||
| 212 | |||
| 213 | 42452 | AtomicExprNode *AssignExprNode::getLhsAtomicNode() const { | |
| 214 |
3/4✓ Branch 2 → 3 taken 42452 times.
✗ Branch 2 → 4 not taken.
✓ Branch 5 → 6 taken 8773 times.
✓ Branch 5 → 7 taken 33679 times.
|
42452 | if (auto *atomicNode = dynamic_cast<AtomicExprNode *>(lhs)) |
| 215 | 8773 | return atomicNode; | |
| 216 |
4/6✓ Branch 7 → 8 taken 33679 times.
✗ Branch 7 → 28 not taken.
✓ Branch 9 → 10 taken 33679 times.
✗ Branch 9 → 11 not taken.
✓ Branch 13 → 14 taken 31655 times.
✓ Branch 13 → 15 taken 2024 times.
|
33679 | if (auto *atomicNode = dynamic_cast<AtomicExprNode *>(lhs->getChildren().back())) |
| 217 | 31655 | return atomicNode; | |
| 218 |
5/8✓ Branch 15 → 16 taken 2024 times.
✗ Branch 15 → 31 not taken.
✓ Branch 17 → 18 taken 2024 times.
✗ Branch 17 → 29 not taken.
✓ Branch 19 → 20 taken 2024 times.
✗ Branch 19 → 21 not taken.
✓ Branch 24 → 25 taken 1537 times.
✓ Branch 24 → 26 taken 487 times.
|
2024 | if (auto *atomicNode = dynamic_cast<AtomicExprNode *>(lhs->getChildren().back()->getChildren().front())) |
| 219 | 1537 | return atomicNode; | |
| 220 | 487 | return nullptr; | |
| 221 | } | ||
| 222 | |||
| 223 | 18 | bool TernaryExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 224 |
3/4✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 5 not taken.
✓ Branch 4 → 5 taken 10 times.
✓ Branch 4 → 6 taken 8 times.
|
18 | const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue(manIdx); |
| 225 |
3/4✓ Branch 7 → 8 taken 18 times.
✗ Branch 7 → 10 not taken.
✓ Branch 9 → 10 taken 12 times.
✓ Branch 9 → 11 taken 6 times.
|
18 | const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue(manIdx); |
| 226 |
1/6✗ Branch 13 → 14 not taken.
✓ Branch 13 → 17 taken 18 times.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 17 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
|
18 | return condition->hasCompileTimeValue(manIdx) && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue; |
| 227 | } | ||
| 228 | |||
| 229 | ✗ | CompileTimeValue TernaryExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 230 | ✗ | assert(condition != nullptr); | |
| 231 | ✗ | if (!trueExpr && !falseExpr) | |
| 232 | ✗ | return condition->getCompileTimeValue(manIdx); | |
| 233 | |||
| 234 | // If the condition has no compile time value, we do not need to evaluate the true and false values | ||
| 235 | ✗ | if (!condition->hasCompileTimeValue(manIdx)) | |
| 236 | ✗ | return {}; | |
| 237 | |||
| 238 | // Check if the condition always evaluates to 'true' | ||
| 239 | ✗ | if (condition->getCompileTimeValue(manIdx).boolValue) { | |
| 240 | ✗ | const ExprNode *trueValue = isShortened ? condition : trueExpr; | |
| 241 | ✗ | assert(trueValue != nullptr); | |
| 242 | ✗ | return trueValue->getCompileTimeValue(manIdx); | |
| 243 | } | ||
| 244 | |||
| 245 | ✗ | assert(falseExpr != nullptr); | |
| 246 | ✗ | return falseExpr->getCompileTimeValue(manIdx); | |
| 247 | } | ||
| 248 | |||
| 249 | 2350 | bool LogicalOrExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 250 | 4700 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 251 | } | ||
| 252 | |||
| 253 | ✗ | CompileTimeValue LogicalOrExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 254 | ✗ | if (operands.size() == 1) | |
| 255 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 256 | |||
| 257 | // Check if one expression evaluates to 'true' | ||
| 258 | ✗ | for (const ExprNode *op : operands) { | |
| 259 | ✗ | assert(op->hasCompileTimeValue(manIdx)); | |
| 260 | // If one operand evaluates to 'true' the whole expression is 'true' | ||
| 261 | ✗ | if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(manIdx); opCompileTimeValue.boolValue) | |
| 262 | ✗ | return CompileTimeValue{.boolValue = true}; | |
| 263 | } | ||
| 264 | |||
| 265 | // Return 'false' | ||
| 266 | ✗ | return CompileTimeValue{.boolValue = false}; | |
| 267 | } | ||
| 268 | |||
| 269 | 2440 | bool LogicalAndExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 270 | 4880 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 271 | } | ||
| 272 | |||
| 273 | ✗ | CompileTimeValue LogicalAndExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 274 | ✗ | if (operands.size() == 1) | |
| 275 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 276 | |||
| 277 | // Check if all expressions evaluate to 'true' | ||
| 278 | ✗ | for (const ExprNode *op : operands) { | |
| 279 | ✗ | assert(op->hasCompileTimeValue(manIdx)); | |
| 280 | // If one operand evaluates to 'false' the whole expression is 'false' | ||
| 281 | ✗ | if (const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(manIdx); !opCompileTimeValue.boolValue) | |
| 282 | ✗ | return CompileTimeValue{.boolValue = false}; | |
| 283 | } | ||
| 284 | |||
| 285 | // Return 'false' | ||
| 286 | ✗ | return CompileTimeValue{.boolValue = false}; | |
| 287 | } | ||
| 288 | |||
| 289 | 506 | bool BitwiseOrExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 290 | 1012 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 291 | } | ||
| 292 | |||
| 293 | ✗ | CompileTimeValue BitwiseOrExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 294 | ✗ | if (operands.size() == 1) | |
| 295 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 296 | |||
| 297 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 298 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 299 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 300 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 301 | ✗ | result.longValue |= opCompileTimeValue.longValue; | |
| 302 | } | ||
| 303 | |||
| 304 | ✗ | return result; | |
| 305 | } | ||
| 306 | |||
| 307 | 2 | bool BitwiseXorExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 308 | 4 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 309 | } | ||
| 310 | |||
| 311 | ✗ | CompileTimeValue BitwiseXorExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 312 | ✗ | if (operands.size() == 1) | |
| 313 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 314 | |||
| 315 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 316 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 317 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 318 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 319 | ✗ | result.longValue ^= opCompileTimeValue.longValue; | |
| 320 | } | ||
| 321 | |||
| 322 | ✗ | return result; | |
| 323 | } | ||
| 324 | |||
| 325 | 32 | bool BitwiseAndExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 326 | 64 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 327 | } | ||
| 328 | |||
| 329 | ✗ | CompileTimeValue BitwiseAndExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 330 | ✗ | if (operands.size() == 1) | |
| 331 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 332 | |||
| 333 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 334 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 335 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 336 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 337 | ✗ | result.longValue &= opCompileTimeValue.longValue; | |
| 338 | } | ||
| 339 | |||
| 340 | ✗ | return result; | |
| 341 | } | ||
| 342 | |||
| 343 | 32740 | bool EqualityExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 344 | 65516 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 345 | } | ||
| 346 | |||
| 347 | 38 | CompileTimeValue EqualityExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 348 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 38 times.
|
38 | if (operands.size() == 1) |
| 349 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 350 | |||
| 351 |
2/4✓ Branch 7 → 8 taken 38 times.
✗ Branch 7 → 34 not taken.
✓ Branch 8 → 9 taken 38 times.
✗ Branch 8 → 34 not taken.
|
38 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(manIdx); |
| 352 |
2/4✓ Branch 9 → 10 taken 38 times.
✗ Branch 9 → 34 not taken.
✓ Branch 10 → 11 taken 38 times.
✗ Branch 10 → 34 not taken.
|
38 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(manIdx); |
| 353 |
2/2✓ Branch 11 → 12 taken 36 times.
✓ Branch 11 → 13 taken 2 times.
|
38 | if (op == EqualityOp::OP_EQUAL) |
| 354 | 36 | return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue}; | |
| 355 |
1/2✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 15 not taken.
|
2 | if (op == EqualityOp::OP_NOT_EQUAL) |
| 356 | 2 | return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue}; | |
| 357 | |||
| 358 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()"); | |
| 359 | } | ||
| 360 | |||
| 361 | 20499 | bool RelationalExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 362 | 41062 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 363 | } | ||
| 364 | |||
| 365 | 82 | CompileTimeValue RelationalExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 366 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 82 times.
|
82 | if (operands.size() == 1) |
| 367 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 368 | |||
| 369 |
2/4✓ Branch 7 → 8 taken 82 times.
✗ Branch 7 → 38 not taken.
✓ Branch 8 → 9 taken 82 times.
✗ Branch 8 → 38 not taken.
|
82 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(manIdx); |
| 370 |
2/4✓ Branch 9 → 10 taken 82 times.
✗ Branch 9 → 38 not taken.
✓ Branch 10 → 11 taken 82 times.
✗ Branch 10 → 38 not taken.
|
82 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(manIdx); |
| 371 |
1/2✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 82 times.
|
82 | if (op == RelationalOp::OP_LESS) |
| 372 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue}; | |
| 373 |
2/2✓ Branch 13 → 14 taken 80 times.
✓ Branch 13 → 15 taken 2 times.
|
82 | if (op == RelationalOp::OP_GREATER) |
| 374 | 80 | return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue}; | |
| 375 |
1/2✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 17 not taken.
|
2 | if (op == RelationalOp::OP_LESS_EQUAL) |
| 376 | 2 | return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue}; | |
| 377 | ✗ | if (op == RelationalOp::OP_GREATER_EQUAL) | |
| 378 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue}; | |
| 379 | |||
| 380 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()"); | |
| 381 | } | ||
| 382 | |||
| 383 | 8 | bool ShiftExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 384 | 16 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 385 | } | ||
| 386 | |||
| 387 | ✗ | CompileTimeValue ShiftExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 388 | ✗ | if (operands.size() == 1) | |
| 389 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 390 | |||
| 391 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 392 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 393 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 394 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 395 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 396 | ✗ | const ShiftOp op = opQueueCopy.front().first; | |
| 397 | ✗ | opQueueCopy.pop(); | |
| 398 | ✗ | if (op == ShiftOp::OP_SHIFT_LEFT) | |
| 399 | ✗ | result.longValue <<= opCompileTimeValue.longValue; | |
| 400 | ✗ | else if (op == ShiftOp::OP_SHIFT_RIGHT) | |
| 401 | ✗ | result.longValue >>= opCompileTimeValue.longValue; | |
| 402 | else | ||
| 403 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()"); | |
| 404 | } | ||
| 405 | ✗ | return result; | |
| 406 | ✗ | } | |
| 407 | |||
| 408 | 1152 | bool AdditiveExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 409 | 2308 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 410 | } | ||
| 411 | |||
| 412 | ✗ | CompileTimeValue AdditiveExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 413 | ✗ | if (operands.size() == 1) | |
| 414 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 415 | |||
| 416 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 417 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 418 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 419 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 420 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 421 | ✗ | const AdditiveOp op = opQueueCopy.front().first; | |
| 422 | ✗ | opQueueCopy.pop(); | |
| 423 | ✗ | if (op == AdditiveOp::OP_PLUS) | |
| 424 | ✗ | result.longValue += opCompileTimeValue.longValue; | |
| 425 | ✗ | else if (op == AdditiveOp::OP_MINUS) | |
| 426 | ✗ | result.longValue -= opCompileTimeValue.longValue; | |
| 427 | else | ||
| 428 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()"); | |
| 429 | } | ||
| 430 | ✗ | return result; | |
| 431 | ✗ | } | |
| 432 | |||
| 433 | 1078 | bool MultiplicativeExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 434 | 2158 | return std::ranges::all_of(operands, [=](const ExprNode *node) { return node->hasCompileTimeValue(manIdx); }); | |
| 435 | } | ||
| 436 | |||
| 437 | ✗ | CompileTimeValue MultiplicativeExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 438 | ✗ | if (operands.size() == 1) | |
| 439 | ✗ | return operands.front()->getCompileTimeValue(manIdx); | |
| 440 | |||
| 441 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(manIdx); | |
| 442 | ✗ | OpQueue opQueueCopy = opQueue; | |
| 443 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
| 444 | ✗ | assert(operands.at(i)->hasCompileTimeValue(manIdx)); | |
| 445 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(manIdx); | |
| 446 | ✗ | const MultiplicativeOp op = opQueueCopy.front().first; | |
| 447 | ✗ | opQueueCopy.pop(); | |
| 448 | ✗ | if (op == MultiplicativeOp::OP_MUL) { | |
| 449 | ✗ | result.longValue *= opCompileTimeValue.longValue; | |
| 450 | ✗ | } else if (op == MultiplicativeOp::OP_DIV) { | |
| 451 | ✗ | if (opCompileTimeValue.longValue == 0) | |
| 452 | ✗ | throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed."); | |
| 453 | ✗ | result.longValue /= opCompileTimeValue.longValue; | |
| 454 | ✗ | } else if (op == MultiplicativeOp::OP_REM) { | |
| 455 | ✗ | result.longValue %= opCompileTimeValue.longValue; | |
| 456 | } else { | ||
| 457 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()"); | |
| 458 | } | ||
| 459 | } | ||
| 460 | ✗ | return result; | |
| 461 | ✗ | } | |
| 462 | |||
| 463 | 1352 | bool CastExprNode::hasCompileTimeValue(size_t manIdx) const { | |
| 464 |
1/2✓ Branch 2 → 3 taken 1352 times.
✗ Branch 2 → 5 not taken.
|
1352 | return isCast ? assignExpr->hasCompileTimeValue(manIdx) : prefixUnaryExpr->hasCompileTimeValue(manIdx); |
| 465 | } | ||
| 466 | |||
| 467 | ✗ | CompileTimeValue CastExprNode::getCompileTimeValue(size_t manIdx) const { | |
| 468 | ✗ | return isCast ? assignExpr->getCompileTimeValue(manIdx) : prefixUnaryExpr->getCompileTimeValue(manIdx); | |
| 469 | } | ||
| 470 | |||
| 471 | 6794 | bool PrefixUnaryExprNode::hasCompileTimeValue(size_t manIdx) const { // NOLINT(*-no-recursion) | |
| 472 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 6794 times.
|
6794 | if (postfixUnaryExpr) |
| 473 | ✗ | return postfixUnaryExpr->hasCompileTimeValue(manIdx); | |
| 474 | |||
| 475 |
3/4✓ Branch 6 → 7 taken 6712 times.
✓ Branch 6 → 11 taken 82 times.
✓ Branch 7 → 8 taken 6712 times.
✗ Branch 7 → 11 not taken.
|
6794 | const bool isSupported = op == PrefixUnaryOp::OP_NONE || op == PrefixUnaryOp::OP_MINUS || op == PrefixUnaryOp::OP_PLUS_PLUS || |
| 476 |
4/6✓ Branch 5 → 6 taken 6794 times.
✗ Branch 5 → 11 not taken.
✓ Branch 8 → 9 taken 6712 times.
✗ Branch 8 → 11 not taken.
✓ Branch 9 → 10 taken 183 times.
✓ Branch 9 → 11 taken 6529 times.
|
13771 | op == PrefixUnaryOp::OP_MINUS_MINUS || op == PrefixUnaryOp::OP_NOT || |
| 477 |
2/2✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 181 times.
|
183 | op == PrefixUnaryOp::OP_BITWISE_NOT; |
| 478 |
4/4✓ Branch 13 → 14 taken 6613 times.
✓ Branch 13 → 17 taken 181 times.
✓ Branch 15 → 16 taken 650 times.
✓ Branch 15 → 17 taken 5963 times.
|
6794 | return isSupported && prefixUnaryExpr->hasCompileTimeValue(manIdx); |
| 479 | } | ||
| 480 | |||
| 481 | 1300 | CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue(size_t manIdx) const { // NOLINT(*-no-recursion) | |
| 482 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 1300 times.
|
1300 | if (postfixUnaryExpr) |
| 483 | ✗ | return postfixUnaryExpr->getCompileTimeValue(manIdx); | |
| 484 | |||
| 485 |
1/2✓ Branch 5 → 6 taken 1300 times.
✗ Branch 5 → 35 not taken.
|
1300 | CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue(manIdx); |
| 486 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1300 times.
|
1300 | if (op == PrefixUnaryOp::OP_MINUS) |
| 487 | ✗ | return CompileTimeValue{.longValue = -opValue.longValue}; | |
| 488 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1300 times.
|
1300 | if (op == PrefixUnaryOp::OP_PLUS_PLUS) |
| 489 | ✗ | return CompileTimeValue{.longValue = ++opValue.longValue}; | |
| 490 |
1/2✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1300 times.
|
1300 | if (op == PrefixUnaryOp::OP_MINUS_MINUS) |
| 491 | ✗ | return CompileTimeValue{.longValue = --opValue.longValue}; | |
| 492 |
1/2✓ Branch 12 → 13 taken 1300 times.
✗ Branch 12 → 14 not taken.
|
1300 | if (op == PrefixUnaryOp::OP_NOT) |
| 493 | 1300 | return CompileTimeValue{.boolValue = !opValue.boolValue}; | |
| 494 | ✗ | if (op == PrefixUnaryOp::OP_BITWISE_NOT) | |
| 495 | ✗ | return CompileTimeValue{.longValue = ~opValue.longValue}; | |
| 496 | |||
| 497 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()"); | |
| 498 | } | ||
| 499 | |||
| 500 | 19558 | bool PostfixUnaryExprNode::hasCompileTimeValue(size_t manIdx) const { // NOLINT(*-no-recursion) | |
| 501 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 19558 times.
|
19558 | if (atomicExpr) |
| 502 | ✗ | return atomicExpr->hasCompileTimeValue(manIdx); | |
| 503 | |||
| 504 | 19558 | const bool isSupported = | |
| 505 |
4/6✓ Branch 5 → 6 taken 19558 times.
✗ Branch 5 → 8 not taken.
✓ Branch 6 → 7 taken 19558 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 8 taken 6 times.
✓ Branch 7 → 9 taken 19552 times.
|
19558 | op == PostfixUnaryOp::OP_NONE || op == PostfixUnaryOp::OP_PLUS_PLUS || op == PostfixUnaryOp::OP_MINUS_MINUS; |
| 506 |
3/4✓ Branch 10 → 11 taken 6 times.
✓ Branch 10 → 14 taken 19552 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 6 times.
|
19558 | return isSupported && postfixUnaryExpr->hasCompileTimeValue(manIdx); |
| 507 | } | ||
| 508 | |||
| 509 | ✗ | CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue(size_t manIdx) const { // NOLINT(*-no-recursion) | |
| 510 | ✗ | if (atomicExpr) | |
| 511 | ✗ | return atomicExpr->getCompileTimeValue(manIdx); | |
| 512 | |||
| 513 | ✗ | CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue(manIdx); | |
| 514 | ✗ | if (op == PostfixUnaryOp::OP_PLUS_PLUS) | |
| 515 | ✗ | return CompileTimeValue{.longValue = opValue.longValue++}; | |
| 516 | ✗ | if (op == PostfixUnaryOp::OP_MINUS_MINUS) | |
| 517 | ✗ | return CompileTimeValue{.longValue = opValue.longValue--}; | |
| 518 | |||
| 519 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()"); | |
| 520 | } | ||
| 521 | |||
| 522 |
4/4✓ Branch 2 → 3 taken 16156 times.
✓ Branch 2 → 5 taken 20 times.
✓ Branch 4 → 5 taken 768 times.
✓ Branch 4 → 6 taken 15388 times.
|
16176 | bool ValueNode::hasCompileTimeValue(size_t manIdx) const { return isNil || ASTNode::hasCompileTimeValue(manIdx); } |
| 523 | |||
| 524 | 2568 | CompileTimeValue ValueNode::getCompileTimeValue(size_t manIdx) const { | |
| 525 |
2/2✓ Branch 2 → 3 taken 1132 times.
✓ Branch 2 → 4 taken 1436 times.
|
2568 | return isNil ? CompileTimeValue{.longValue = 0} : ASTNode::getCompileTimeValue(manIdx); |
| 526 | } | ||
| 527 | |||
| 528 | 31768 | bool FctCallNode::hasCompileTimeValue(size_t manIdx) const { | |
| 529 |
6/8✓ Branch 3 → 4 taken 31768 times.
✗ Branch 3 → 11 not taken.
✓ Branch 4 → 5 taken 16450 times.
✓ Branch 4 → 8 taken 15318 times.
✓ Branch 5 → 6 taken 16450 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 3868 times.
✓ Branch 6 → 8 taken 12582 times.
|
31768 | return BUILTIN_FUNCTIONS_MAP.contains(fqFunctionName) && data.at(manIdx).compileTimeValueSet; |
| 530 | } | ||
| 531 | |||
| 532 | 4536 | CompileTimeValue FctCallNode::getCompileTimeValue(size_t manIdx) const { return data.at(manIdx).compileTimeValue; } | |
| 533 | |||
| 534 | 782 | void FctCallNode::setCompileTimeValue(const CompileTimeValue &value, size_t manIdx) { | |
| 535 | 782 | data.at(manIdx).setCompileTimeValue(value); | |
| 536 | 782 | } | |
| 537 | |||
| 538 | 44493 | bool FctCallNode::returnsOnAllControlPaths(bool *overrideUnreachable, size_t manIdx) const { | |
| 539 | // Some builtin functions terminate the control flow, e.g. panic | ||
| 540 |
1/2✓ Branch 3 → 4 taken 44493 times.
✗ Branch 3 → 13 not taken.
|
44493 | const auto it = BUILTIN_FUNCTIONS_MAP.find(fqFunctionName); |
| 541 |
4/4✓ Branch 6 → 7 taken 8052 times.
✓ Branch 6 → 10 taken 36441 times.
✓ Branch 8 → 9 taken 5323 times.
✓ Branch 8 → 10 taken 2729 times.
|
44493 | return it != BUILTIN_FUNCTIONS_MAP.end() && it->second.isFunctionTerminator; |
| 542 | } | ||
| 543 | |||
| 544 | /** | ||
| 545 | * Check if right above the closest assign expression ancestor is a statement node | ||
| 546 | * | ||
| 547 | * @return Has return value receiver or not | ||
| 548 | */ | ||
| 549 | 84548 | bool FctCallNode::hasReturnValueReceiver() const { | |
| 550 | 84548 | const ASTNode *node = parent; | |
| 551 |
2/2✓ Branch 13 → 3 taken 299867 times.
✓ Branch 13 → 14 taken 6898 times.
|
306765 | while (!node->isAssignExpr()) { |
| 552 |
2/2✓ Branch 4 → 5 taken 9550 times.
✓ Branch 4 → 6 taken 290317 times.
|
299867 | if (node->isExprStmt()) |
| 553 | 9550 | return false; | |
| 554 | // As soon as we have a node with more than one child, we know that the return value is used | ||
| 555 |
3/4✓ Branch 6 → 7 taken 290317 times.
✗ Branch 6 → 25 not taken.
✓ Branch 9 → 10 taken 68100 times.
✓ Branch 9 → 11 taken 222217 times.
|
290317 | if (node->getChildren().size() > 1) |
| 556 | 68100 | return true; | |
| 557 | 222217 | node = node->parent; | |
| 558 | } | ||
| 559 | // Also check the condition of the assign expression | ||
| 560 |
3/12✓ Branch 14 → 15 taken 6898 times.
✗ Branch 14 → 26 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 6898 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 26 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
✓ Branch 21 → 22 taken 6898 times.
✗ Branch 21 → 23 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
|
6898 | return node->getChildren().size() > 1 || !node->parent->isExprStmt(); |
| 561 | } | ||
| 562 | |||
| 563 | 109 | bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable, size_t manIdx) const { | |
| 564 | 109 | return body->returnsOnAllControlPaths(overrideUnreachable, manIdx); | |
| 565 | } | ||
| 566 | |||
| 567 | 92 | bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable, size_t manIdx) const { | |
| 568 | 92 | return body->returnsOnAllControlPaths(overrideUnreachable, manIdx); | |
| 569 | } | ||
| 570 | |||
| 571 | 17891 | void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion) | |
| 572 | // Set the current node to field type | ||
| 573 | 17891 | isFieldType = true; | |
| 574 | // Do the same for all template nodes | ||
| 575 |
4/4✓ Branch 2 → 3 taken 9956 times.
✓ Branch 2 → 20 taken 7935 times.
✓ Branch 3 → 4 taken 1439 times.
✓ Branch 3 → 20 taken 8517 times.
|
17891 | if (const CustomDataTypeNode *customType = baseDataType->customDataType; customType != nullptr && customType->templateTypeLst) |
| 576 |
2/2✓ Branch 18 → 6 taken 1970 times.
✓ Branch 18 → 19 taken 1439 times.
|
4848 | for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes) |
| 577 |
1/2✓ Branch 8 → 9 taken 1970 times.
✗ Branch 8 → 21 not taken.
|
1970 | templateNode->setFieldTypeRecursive(); |
| 578 | 17891 | } | |
| 579 | |||
| 580 | } // namespace spice::compiler | ||
| 581 |