Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include <ast/ASTNodes.h> | ||
4 | |||
5 | #include "SourceFile.h" | ||
6 | #include <ast/Attributes.h> | ||
7 | #include <exception/SemanticError.h> | ||
8 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
9 | |||
10 | namespace spice::compiler { | ||
11 | |||
12 | // Constant definitions | ||
13 | static constexpr size_t ERROR_MESSAGE_CONTEXT = 20; | ||
14 | |||
15 | 533 | std::string ASTNode::getErrorMessage() const { | |
16 | 533 | antlr4::CharStream *inputStream = codeLoc.sourceFile->antlrCtx.inputStream.get(); | |
17 | 533 | const antlr4::misc::Interval &sourceInterval = codeLoc.sourceInterval; | |
18 | 533 | antlr4::misc::Interval extSourceInterval(sourceInterval); | |
19 | |||
20 | // If we have a multi-line interval, only use the first line | ||
21 |
3/4✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 514 times.
|
533 | if (const size_t offset = inputStream->getText(extSourceInterval).find('\n'); offset != std::string::npos) |
22 | 19 | extSourceInterval.b = extSourceInterval.a + static_cast<ssize_t>(offset); | |
23 | |||
24 | 533 | size_t markerIndentation = 0; | |
25 |
2/2✓ Branch 0 taken 5486 times.
✓ Branch 1 taken 125 times.
|
5611 | for (; markerIndentation < ERROR_MESSAGE_CONTEXT; markerIndentation++) { |
26 | 5486 | extSourceInterval.a--; | |
27 |
9/12✓ Branch 0 taken 5471 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 5471 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 393 times.
✓ Branch 7 taken 5078 times.
✓ Branch 8 taken 5471 times.
✓ Branch 9 taken 15 times.
✓ Branch 11 taken 408 times.
✓ Branch 12 taken 5078 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
5486 | if (extSourceInterval.a < 0 || inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
28 | 408 | extSourceInterval.a++; | |
29 | 408 | break; | |
30 | } | ||
31 | } | ||
32 |
2/2✓ Branch 0 taken 1622 times.
✓ Branch 1 taken 8 times.
|
1630 | for (size_t suffixContext = 0; suffixContext < ERROR_MESSAGE_CONTEXT; suffixContext++) { |
33 | 1622 | extSourceInterval.b++; | |
34 |
4/6✓ Branch 1 taken 1622 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1622 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 525 times.
✓ Branch 6 taken 1097 times.
|
3244 | if (static_cast<size_t>(extSourceInterval.b) > inputStream->size() || |
35 |
4/8✓ Branch 1 taken 1622 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1622 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 525 times.
✓ Branch 8 taken 1097 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
3244 | inputStream->getText(extSourceInterval).find('\n') != std::string::npos) { |
36 | 525 | extSourceInterval.b--; | |
37 | 525 | break; | |
38 | } | ||
39 | } | ||
40 | |||
41 | // Trim start | ||
42 |
4/6✓ Branch 1 taken 2713 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2713 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2180 times.
✓ Branch 8 taken 533 times.
|
2713 | while (inputStream->getText(extSourceInterval)[0] == ' ') { |
43 | 2180 | extSourceInterval.a++; | |
44 | 2180 | markerIndentation--; | |
45 | } | ||
46 | |||
47 | // Trim end | ||
48 |
4/6✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 533 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 19 times.
✓ Branch 9 taken 514 times.
|
533 | if (inputStream->getText(extSourceInterval)[extSourceInterval.length() - 1] == '\n') |
49 | 19 | extSourceInterval.b--; | |
50 | |||
51 | 533 | const std::string lineNumberStr = std::to_string(codeLoc.line); | |
52 | 533 | markerIndentation += lineNumberStr.length() + 2; | |
53 | |||
54 | // Build error message | ||
55 |
1/2✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
|
533 | std::stringstream ss; |
56 |
5/10✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 533 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 533 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 533 times.
✗ Branch 14 not taken.
|
533 | ss << lineNumberStr << " " << inputStream->getText(extSourceInterval) << "\n"; |
57 |
2/4✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
|
1066 | ss << std::string(markerIndentation, ' '); |
58 |
2/4✓ Branch 4 taken 533 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 533 times.
✗ Branch 8 not taken.
|
533 | ss << std::string(std::min(sourceInterval.length(), extSourceInterval.length()), '^'); |
59 |
1/2✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
|
1066 | return ss.str(); |
60 | 533 | } | |
61 | |||
62 | 18388 | const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion) | |
63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18388 times.
|
18388 | assert(parent != nullptr && "Could not find next outer statement list"); |
64 |
2/2✓ Branch 1 taken 12472 times.
✓ Branch 2 taken 5916 times.
|
30860 | return isStmtLstNode() ? spice_pointer_cast<const StmtLstNode *>(this) : parent->getNextOuterStmtLst(); |
65 | } | ||
66 | |||
67 | 343 | bool MainFctDefNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
68 | 343 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
69 | } | ||
70 | |||
71 | 6947 | bool FctDefBaseNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
72 | 6947 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
73 | } | ||
74 | |||
75 | 806 | bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
76 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
77 | // we can assume that the loop itself will always return | ||
78 |
7/12✓ Branch 1 taken 806 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 806 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 805 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
|
806 | const bool loopConditionAlwaysTrue = condAssign()->hasCompileTimeValue() && condAssign()->getCompileTimeValue().boolValue; |
79 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 806 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
806 | return loopConditionAlwaysTrue && body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
80 | } | ||
81 | |||
82 | 381 | bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
83 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
84 | // we can assume that the loop itself will always return | ||
85 |
8/12✓ Branch 1 taken 381 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 381 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 377 times.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 1 times.
|
381 | const bool loopConditionAlwaysTrue = condition()->hasCompileTimeValue() && condition()->getCompileTimeValue().boolValue; |
86 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 378 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
|
381 | return loopConditionAlwaysTrue && body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
87 | } | ||
88 | |||
89 | 9 | bool DoWhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
90 | // Do-while loops will always be executed at least once. So if the body returns on all control paths, the loop will as well | ||
91 | 9 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
92 | } | ||
93 | |||
94 | 2339 | bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
95 | // If the condition always evaluates to 'true' the then block must return | ||
96 | 2339 | const AssignExprNode *cond = condition(); | |
97 |
8/10✓ Branch 1 taken 2339 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 2327 times.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 2335 times.
|
2339 | if (cond->hasCompileTimeValue() && cond->getCompileTimeValue().boolValue) |
98 | 4 | return thenBody()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
99 | |||
100 | // If the condition always evaluates to 'false' the else block must return | ||
101 |
7/10✓ Branch 1 taken 2335 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 2327 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 2327 times.
|
2335 | if (cond->hasCompileTimeValue() && !cond->getCompileTimeValue().boolValue) |
102 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
|
8 | return elseStmt() != nullptr && elseStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
103 | |||
104 | // If the condition does not always evaluate to 'true' or 'false' we need to check both branches | ||
105 |
4/4✓ Branch 2 taken 1665 times.
✓ Branch 3 taken 662 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 1636 times.
|
2356 | return thenBody()->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt() != nullptr && |
106 |
1/2✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
2356 | elseStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
107 | } | ||
108 | |||
109 | 31 | bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
110 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 21 times.
|
31 | if (isElseIf) |
111 | 10 | return ifStmt()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
112 | 21 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
113 | } | ||
114 | |||
115 | 8 | bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
116 | 23 | const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); }; | |
117 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches(), pred); |
118 |
6/10✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 5 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
|
8 | const bool defaultBranchReturns = !defaultBranch() || defaultBranch()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
119 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
16 | return allCaseBranchesReturn && defaultBranchReturns; |
120 | } | ||
121 | |||
122 | 23 | bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
123 | 23 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
124 | } | ||
125 | |||
126 | 3 | bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
127 | 3 | return body()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
128 | } | ||
129 | |||
130 | 11282 | bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
131 | // An empty statement list does not return at all | ||
132 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 11254 times.
|
11282 | if (children.empty()) |
133 | 28 | return false; | |
134 | // A statement list returns on all control paths, if the one direct child statement returns on all control paths | ||
135 | 11254 | bool returnsOnAllControlPaths = false; | |
136 |
2/2✓ Branch 5 taken 22809 times.
✓ Branch 6 taken 11254 times.
|
34063 | for (ASTNode *child : children) { |
137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22809 times.
|
22809 | assert(child != nullptr); |
138 | |||
139 | // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false | ||
140 |
4/4✓ Branch 0 taken 588 times.
✓ Branch 1 taken 22221 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 583 times.
|
22809 | if (returnsOnAllControlPaths && *doSetPredecessorsUnreachable) |
141 | 5 | child->unreachable = true; | |
142 | |||
143 |
3/4✓ Branch 1 taken 22809 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6336 times.
✓ Branch 4 taken 16473 times.
|
22809 | if (child->returnsOnAllControlPaths(doSetPredecessorsUnreachable)) |
144 | 6336 | returnsOnAllControlPaths = true; | |
145 | } | ||
146 | 11254 | return returnsOnAllControlPaths; | |
147 | } | ||
148 | |||
149 | 1304 | std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const { | |
150 |
2/4✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1304 times.
|
1304 | assert(ATTR_CONFIGS.contains(key)); |
151 |
1/2✓ Branch 1 taken 1304 times.
✗ Branch 2 not taken.
|
1304 | const std::vector<AttrNode *> attrNodes = attributes(); |
152 | |||
153 | 1304 | std::vector<const CompileTimeValue *> attributeValues; | |
154 |
2/2✓ Branch 5 taken 1965 times.
✓ Branch 6 taken 1304 times.
|
3269 | for (const AttrNode *attrNode : attrNodes) { |
155 | // Skip attributes with different keys | ||
156 |
2/2✓ Branch 1 taken 1314 times.
✓ Branch 2 taken 651 times.
|
1965 | if (attrNode->key != key) |
157 | 1314 | continue; | |
158 | |||
159 | // Found a matching attribute | ||
160 |
1/2✓ Branch 1 taken 651 times.
✗ Branch 2 not taken.
|
651 | const CompileTimeValue *value = attrNode->getValue(); |
161 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 597 times.
|
651 | if (!value) { |
162 | // If the attribute has no value, we use the default value | ||
163 |
1/2✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
|
54 | attributeValues.push_back(&DEFAULT_BOOL_COMPILE_VALUE); |
164 | } else { | ||
165 | // If the attribute has a value, we use the value | ||
166 |
1/2✓ Branch 1 taken 597 times.
✗ Branch 2 not taken.
|
597 | attributeValues.push_back(value); |
167 | } | ||
168 | } | ||
169 | |||
170 | 2608 | return attributeValues; | |
171 | 1304 | } | |
172 | |||
173 | 476 | const CompileTimeValue *AttrLstNode::getAttrValueByName(const std::string &key) const { | |
174 |
1/2✓ Branch 1 taken 476 times.
✗ Branch 2 not taken.
|
476 | const std::vector<const CompileTimeValue *> attrs = getAttrValuesByName(key); |
175 |
2/2✓ Branch 1 taken 35 times.
✓ Branch 2 taken 441 times.
|
952 | return attrs.empty() ? nullptr : attrs.back(); |
176 | 476 | } | |
177 | |||
178 | 788 | bool AttrLstNode::hasAttr(const std::string &key) const { | |
179 |
1/2✓ Branch 1 taken 788 times.
✗ Branch 2 not taken.
|
788 | const std::vector<AttrNode *> attrs = attributes(); |
180 |
1/2✓ Branch 1 taken 788 times.
✗ Branch 2 not taken.
|
2786 | return std::ranges::any_of(attrs, [&](const AttrNode *attr) { return attr->key == key; }); |
181 | 788 | } | |
182 | |||
183 |
2/2✓ Branch 1 taken 597 times.
✓ Branch 2 taken 54 times.
|
651 | const CompileTimeValue *AttrNode::getValue() const { return value() ? &value()->compileTimeValue : nullptr; } |
184 | |||
185 | 607 | bool AssertStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
186 | // If the expression, passed to the assert statement is always evaluated to false, the assert statement will never succeed | ||
187 |
8/12✓ Branch 1 taken 607 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 607 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 604 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 1 times.
|
607 | return assignExpr()->hasCompileTimeValue() && !assignExpr()->getCompileTimeValue().boolValue; |
188 | } | ||
189 | |||
190 | 9852 | bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
191 | // If it's a ternary, do the default thing | ||
192 |
2/2✓ Branch 0 taken 5530 times.
✓ Branch 1 taken 4322 times.
|
9852 | if (op == OP_NONE) |
193 | 5530 | return children.front()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
194 | |||
195 | // If it's a modification on the result variable, we technically return from the function, but at the end of the function. | ||
196 |
4/4✓ Branch 2 taken 4317 times.
✓ Branch 3 taken 5 times.
✓ Branch 7 taken 843 times.
✓ Branch 8 taken 3474 times.
|
4322 | const bool hasAtomicExpr = lhs()->postfixUnaryExpr() && lhs()->postfixUnaryExpr()->atomicExpr(); |
197 |
6/6✓ Branch 0 taken 843 times.
✓ Branch 1 taken 3479 times.
✓ Branch 6 taken 358 times.
✓ Branch 7 taken 485 times.
✓ Branch 8 taken 358 times.
✓ Branch 9 taken 3964 times.
|
4322 | if (hasAtomicExpr && lhs()->postfixUnaryExpr()->atomicExpr()->fqIdentifier == RETURN_VARIABLE_NAME) { |
198 | // If we assign the result variable, we technically return from the function, but at the end of the function. | ||
199 | // Therefore, the following code is not unreachable, but will be executed in any case. | ||
200 | 358 | *doSetPredecessorsUnreachable = false; | |
201 | 358 | return true; | |
202 | } | ||
203 | |||
204 | 3964 | return false; | |
205 | } | ||
206 | |||
207 | 7048 | bool TernaryExprNode::hasCompileTimeValue() const { | |
208 |
2/4✓ Branch 1 taken 7048 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7048 times.
✗ Branch 5 not taken.
|
14096 | return std::ranges::all_of(operands(), [](const LogicalOrExprNode *node) { return node->hasCompileTimeValue(); }); |
209 | } | ||
210 | |||
211 | 32 | CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant()->getCompileTimeValue(); } | |
212 | |||
213 | 79 | CompileTimeValue TernaryExprNode::getCompileTimeValue() const { | |
214 |
1/2✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
|
79 | if (children.size() == 1) |
215 |
1/2✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
|
79 | return children.front()->getCompileTimeValue(); |
216 | |||
217 | ✗ | const std::vector<LogicalOrExprNode *> &ops = operands(); | |
218 | |||
219 | // If the condition has no compile time value, we do not need to evaluate the true and false values | ||
220 | ✗ | const LogicalOrExprNode *condition = ops[0]; | |
221 | ✗ | if (!condition->hasCompileTimeValue()) | |
222 | ✗ | return {}; | |
223 | |||
224 | // Check if condition always evaluates to 'true' | ||
225 | ✗ | if (condition->getCompileTimeValue().boolValue) { | |
226 | ✗ | const LogicalOrExprNode *trueValue = isShortened ? condition : ops[1]; | |
227 | ✗ | return trueValue->getCompileTimeValue(); | |
228 | } else { | ||
229 | ✗ | const LogicalOrExprNode *falseValue = isShortened ? operands()[1] : ops[2]; | |
230 | ✗ | return falseValue->getCompileTimeValue(); | |
231 | } | ||
232 | ✗ | } | |
233 | |||
234 | 7048 | bool LogicalOrExprNode::hasCompileTimeValue() const { | |
235 |
2/4✓ Branch 1 taken 7048 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7048 times.
✗ Branch 5 not taken.
|
14098 | return std::ranges::all_of(operands(), [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); }); |
236 | } | ||
237 | |||
238 | 79 | CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const { | |
239 |
2/2✓ Branch 1 taken 77 times.
✓ Branch 2 taken 2 times.
|
79 | if (children.size() == 1) |
240 | 77 | return children.front()->getCompileTimeValue(); | |
241 | |||
242 | // Check if one expression evaluates to 'true' | ||
243 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 2 times.
|
6 | for (const LogicalAndExprNode *op : operands()) { |
244 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
245 | // If one operand evaluates to 'true' the whole expression is 'true' | ||
246 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); |
247 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (opCompileTimeValue.boolValue) |
248 | ✗ | return CompileTimeValue{.boolValue = true}; | |
249 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | } |
250 | |||
251 | // Return 'false' | ||
252 | 2 | return CompileTimeValue{.boolValue = false}; | |
253 | } | ||
254 | |||
255 | 7054 | bool LogicalAndExprNode::hasCompileTimeValue() const { | |
256 |
2/4✓ Branch 1 taken 7054 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7054 times.
✗ Branch 5 not taken.
|
14110 | return std::ranges::all_of(operands(), [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); }); |
257 | } | ||
258 | |||
259 | 81 | CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const { | |
260 |
2/2✓ Branch 1 taken 79 times.
✓ Branch 2 taken 2 times.
|
81 | if (children.size() == 1) |
261 | 79 | return children.front()->getCompileTimeValue(); | |
262 | |||
263 | // Check if all expressions evaluate to 'true' | ||
264 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 | for (const BitwiseOrExprNode *op : operands()) { |
265 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
266 | // If one operand evaluates to 'false' the whole expression is 'false' | ||
267 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); |
268 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (!opCompileTimeValue.boolValue) |
269 | 2 | return CompileTimeValue{.boolValue = false}; | |
270 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | } |
271 | |||
272 | // Return 'false' | ||
273 | ✗ | return CompileTimeValue{.boolValue = false}; | |
274 | } | ||
275 | |||
276 | 7060 | bool BitwiseOrExprNode::hasCompileTimeValue() const { | |
277 |
2/4✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
|
14120 | return std::ranges::all_of(operands(), [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); }); |
278 | } | ||
279 | |||
280 | 83 | CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const { | |
281 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
282 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
283 | |||
284 | ✗ | const std::vector<BitwiseXorExprNode *> ops = operands(); | |
285 | ✗ | CompileTimeValue result = ops.front()->getCompileTimeValue(); | |
286 | ✗ | for (size_t i = 1; i < ops.size(); i++) { | |
287 | ✗ | assert(ops.at(i)->hasCompileTimeValue()); | |
288 | ✗ | const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue(); | |
289 | ✗ | result.longValue |= opCompileTimeValue.longValue; | |
290 | } | ||
291 | |||
292 | ✗ | return result; | |
293 | ✗ | } | |
294 | |||
295 | 7060 | bool BitwiseXorExprNode::hasCompileTimeValue() const { | |
296 |
2/4✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
|
14120 | return std::ranges::all_of(operands(), [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); }); |
297 | } | ||
298 | |||
299 | 83 | CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const { | |
300 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
301 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
302 | |||
303 | ✗ | const std::vector<BitwiseAndExprNode *> ops = operands(); | |
304 | ✗ | CompileTimeValue result = ops.front()->getCompileTimeValue(); | |
305 | ✗ | for (size_t i = 1; i < ops.size(); i++) { | |
306 | ✗ | assert(ops.at(i)->hasCompileTimeValue()); | |
307 | ✗ | const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue(); | |
308 | ✗ | result.longValue ^= opCompileTimeValue.longValue; | |
309 | } | ||
310 | |||
311 | ✗ | return result; | |
312 | ✗ | } | |
313 | |||
314 | 7060 | bool BitwiseAndExprNode::hasCompileTimeValue() const { | |
315 |
2/4✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
|
14120 | return std::ranges::all_of(operands(), [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); }); |
316 | } | ||
317 | |||
318 | 83 | CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const { | |
319 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
320 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
321 | |||
322 | ✗ | const std::vector<EqualityExprNode *> ops = operands(); | |
323 | ✗ | CompileTimeValue result = ops.front()->getCompileTimeValue(); | |
324 | ✗ | for (size_t i = 1; i < ops.size(); i++) { | |
325 | ✗ | assert(ops.at(i)->hasCompileTimeValue()); | |
326 | ✗ | const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue(); | |
327 | ✗ | result.longValue &= opCompileTimeValue.longValue; | |
328 | } | ||
329 | |||
330 | ✗ | return result; | |
331 | ✗ | } | |
332 | |||
333 | 7060 | bool EqualityExprNode::hasCompileTimeValue() const { | |
334 |
2/4✓ Branch 1 taken 7060 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7060 times.
✗ Branch 5 not taken.
|
14127 | return std::ranges::all_of(operands(), [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); }); |
335 | } | ||
336 | |||
337 | 83 | CompileTimeValue EqualityExprNode::getCompileTimeValue() const { | |
338 |
2/2✓ Branch 1 taken 76 times.
✓ Branch 2 taken 7 times.
|
83 | if (children.size() == 1) |
339 |
1/2✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
76 | return children.front()->getCompileTimeValue(); |
340 | |||
341 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const std::vector<RelationalExprNode *> ops = operands(); |
342 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue(); |
343 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue(); |
344 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (op == OP_EQUAL) |
345 | 2 | return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue}; | |
346 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (op == OP_NOT_EQUAL) |
347 | 5 | return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue}; | |
348 | |||
349 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()"); | |
350 | 7 | } | |
351 | |||
352 | 7067 | bool RelationalExprNode::hasCompileTimeValue() const { | |
353 |
2/4✓ Branch 1 taken 7067 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7067 times.
✗ Branch 5 not taken.
|
14135 | return std::ranges::all_of(operands(), [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); }); |
354 | } | ||
355 | |||
356 | 90 | CompileTimeValue RelationalExprNode::getCompileTimeValue() const { | |
357 |
2/2✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
|
90 | if (children.size() == 1) |
358 |
1/2✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
|
89 | return children.front()->getCompileTimeValue(); |
359 | |||
360 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const std::vector<ShiftExprNode *> ops = operands(); |
361 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue(); |
362 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue(); |
363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (op == OP_LESS) |
364 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue}; | |
365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (op == OP_GREATER) |
366 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue}; | |
367 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (op == OP_LESS_EQUAL) |
368 | 1 | return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue}; | |
369 | ✗ | if (op == OP_GREATER_EQUAL) | |
370 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue}; | |
371 | |||
372 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()"); | |
373 | 1 | } | |
374 | |||
375 | 7068 | bool ShiftExprNode::hasCompileTimeValue() const { | |
376 |
2/4✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
|
14136 | return std::ranges::all_of(operands(), [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); }); |
377 | } | ||
378 | |||
379 | 91 | CompileTimeValue ShiftExprNode::getCompileTimeValue() const { | |
380 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
381 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
382 | |||
383 | ✗ | const std::vector<AdditiveExprNode *> ops = operands(); | |
384 | ✗ | const CompileTimeValue op0Value = ops.at(0)->getCompileTimeValue(); | |
385 | ✗ | const CompileTimeValue op1Value = ops.at(1)->getCompileTimeValue(); | |
386 | ✗ | if (op == OP_SHIFT_LEFT) | |
387 | ✗ | return CompileTimeValue{.longValue = op0Value.longValue << op1Value.longValue}; | |
388 | ✗ | if (op == OP_SHIFT_RIGHT) | |
389 | ✗ | return CompileTimeValue{.longValue = op0Value.longValue >> op1Value.longValue}; | |
390 | |||
391 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()"); | |
392 | ✗ | } | |
393 | |||
394 | 7068 | bool AdditiveExprNode::hasCompileTimeValue() const { | |
395 |
2/4✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
|
14136 | return std::ranges::all_of(operands(), [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); }); |
396 | } | ||
397 | |||
398 | 91 | CompileTimeValue AdditiveExprNode::getCompileTimeValue() const { | |
399 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
400 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
401 | |||
402 | ✗ | const std::vector<MultiplicativeExprNode *> ops = operands(); | |
403 | ✗ | CompileTimeValue result = ops.front()->getCompileTimeValue(); | |
404 | ✗ | OpQueue opQueueCopy = opQueue; | |
405 | ✗ | for (size_t i = 1; i < ops.size(); i++) { | |
406 | ✗ | assert(ops.at(i)->hasCompileTimeValue()); | |
407 | ✗ | const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue(); | |
408 | ✗ | const AdditiveOp op = opQueueCopy.front().first; | |
409 | ✗ | opQueueCopy.pop(); | |
410 | ✗ | if (op == OP_PLUS) | |
411 | ✗ | result.longValue += opCompileTimeValue.longValue; | |
412 | ✗ | else if (op == OP_MINUS) | |
413 | ✗ | result.longValue -= opCompileTimeValue.longValue; | |
414 | else | ||
415 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()"); | |
416 | } | ||
417 | ✗ | return result; | |
418 | ✗ | } | |
419 | |||
420 | 7068 | bool MultiplicativeExprNode::hasCompileTimeValue() const { | |
421 |
2/4✓ Branch 1 taken 7068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7068 times.
✗ Branch 5 not taken.
|
14136 | return std::ranges::all_of(operands(), [](const CastExprNode *node) { return node->hasCompileTimeValue(); }); |
422 | } | ||
423 | |||
424 | 91 | CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const { | |
425 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
426 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
427 | |||
428 | ✗ | const std::vector<CastExprNode *> ops = operands(); | |
429 | ✗ | CompileTimeValue result = ops.front()->getCompileTimeValue(); | |
430 | ✗ | OpQueue opQueueCopy = opQueue; | |
431 | ✗ | for (size_t i = 1; i < ops.size(); i++) { | |
432 | ✗ | assert(ops.at(i)->hasCompileTimeValue()); | |
433 | ✗ | const CompileTimeValue opCompileTimeValue = ops.at(i)->getCompileTimeValue(); | |
434 | ✗ | const MultiplicativeOp op = opQueueCopy.front().first; | |
435 | ✗ | opQueueCopy.pop(); | |
436 | ✗ | if (op == OP_MUL) { | |
437 | ✗ | result.longValue *= opCompileTimeValue.longValue; | |
438 | ✗ | } else if (op == OP_DIV) { | |
439 | ✗ | if (opCompileTimeValue.longValue == 0) | |
440 | ✗ | throw SemanticError(ops.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed."); | |
441 | ✗ | result.longValue /= opCompileTimeValue.longValue; | |
442 | ✗ | } else if (op == OP_REM) { | |
443 | ✗ | result.longValue %= opCompileTimeValue.longValue; | |
444 | } else { | ||
445 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()"); | |
446 | } | ||
447 | } | ||
448 | ✗ | return result; | |
449 | ✗ | } | |
450 | |||
451 | 7068 | bool CastExprNode::hasCompileTimeValue() const { return prefixUnaryExpr()->hasCompileTimeValue(); } | |
452 | |||
453 | 91 | CompileTimeValue CastExprNode::getCompileTimeValue() const { | |
454 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
455 | 91 | return children.front()->getCompileTimeValue(); | |
456 | |||
457 | ✗ | return prefixUnaryExpr()->getCompileTimeValue(); | |
458 | } | ||
459 | |||
460 | 7317 | bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
461 |
2/2✓ Branch 1 taken 7044 times.
✓ Branch 2 taken 273 times.
|
7317 | if (postfixUnaryExpr()) |
462 | 7044 | return postfixUnaryExpr()->hasCompileTimeValue(); | |
463 | |||
464 | 273 | const bool isOperatorSupported = | |
465 |
7/12✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 273 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 273 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✓ Branch 9 taken 249 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 24 times.
|
273 | op == OP_NONE || op == OP_MINUS || op == OP_PLUS_PLUS || op == OP_MINUS_MINUS || op == OP_NOT || op == OP_BITWISE_NOT; |
466 |
3/4✓ Branch 0 taken 249 times.
✓ Branch 1 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 249 times.
|
273 | return isOperatorSupported && prefixUnary()->hasCompileTimeValue(); |
467 | } | ||
468 | |||
469 | 91 | CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
470 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
|
91 | if (postfixUnaryExpr()) |
471 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
|
91 | return postfixUnaryExpr()->getCompileTimeValue(); |
472 | |||
473 | ✗ | CompileTimeValue opValue = prefixUnary()->getCompileTimeValue(); | |
474 | ✗ | if (op == OP_MINUS) | |
475 | ✗ | return CompileTimeValue{.longValue = -opValue.longValue}; | |
476 | ✗ | if (op == OP_PLUS_PLUS) | |
477 | ✗ | return CompileTimeValue{.longValue = ++opValue.longValue}; | |
478 | ✗ | if (op == OP_MINUS_MINUS) | |
479 | ✗ | return CompileTimeValue{.longValue = --opValue.longValue}; | |
480 | ✗ | if (op == OP_NOT) | |
481 | ✗ | return CompileTimeValue{.boolValue = !opValue.boolValue}; | |
482 | ✗ | if (op == OP_BITWISE_NOT) | |
483 | ✗ | return CompileTimeValue{.longValue = ~opValue.longValue}; | |
484 | |||
485 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()"); | |
486 | } | ||
487 | |||
488 | 7044 | bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
489 |
2/2✓ Branch 1 taken 5524 times.
✓ Branch 2 taken 1520 times.
|
7044 | if (atomicExpr()) |
490 | 5524 | return atomicExpr()->hasCompileTimeValue(); | |
491 | |||
492 |
3/6✓ Branch 0 taken 1520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1520 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1520 times.
|
1520 | const bool isOperatorSupported = op == OP_NONE || op == OP_PLUS_PLUS || op == OP_MINUS_MINUS; |
493 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1520 | return isOperatorSupported && postfixUnaryExpr()->hasCompileTimeValue(); |
494 | } | ||
495 | |||
496 | 91 | CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
497 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
|
91 | if (atomicExpr()) |
498 |
2/4✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
|
91 | return atomicExpr()->getCompileTimeValue(); |
499 | |||
500 | ✗ | CompileTimeValue opValue = postfixUnaryExpr()->getCompileTimeValue(); | |
501 | ✗ | if (op == OP_PLUS_PLUS) | |
502 | ✗ | return CompileTimeValue{.longValue = opValue.longValue++}; | |
503 | ✗ | if (op == OP_MINUS_MINUS) | |
504 | ✗ | return CompileTimeValue{.longValue = opValue.longValue--}; | |
505 | |||
506 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()"); | |
507 | } | ||
508 | |||
509 | /** | ||
510 | * Check if right above the closest assign expression ancestor is a statement node | ||
511 | * | ||
512 | * @return Has return value receiver or not | ||
513 | */ | ||
514 | 6376 | bool FctCallNode::hasReturnValueReceiver() const { | |
515 | 6376 | const ASTNode *node = parent; | |
516 |
2/2✓ Branch 1 taken 94813 times.
✓ Branch 2 taken 5117 times.
|
99930 | while (!node->isAssignExpr()) { |
517 | // As soon as we have a node with more than one child, we know that the return value is used | ||
518 |
2/2✓ Branch 1 taken 1259 times.
✓ Branch 2 taken 93554 times.
|
94813 | if (node->children.size() > 1) |
519 | 1259 | return true; | |
520 | 93554 | node = node->parent; | |
521 | } | ||
522 | // Also check the condition of the assign expression | ||
523 |
3/4✓ Branch 1 taken 5117 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4985 times.
✓ Branch 5 taken 132 times.
|
5117 | return node->children.size() > 1 || !node->parent->isStmtLstNode(); |
524 | } | ||
525 | |||
526 | 9 | bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
527 | 9 | return body()->returnsOnAllControlPaths(overrideUnreachable); | |
528 | } | ||
529 | |||
530 | 38 | bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
531 | 38 | return body()->returnsOnAllControlPaths(overrideUnreachable); | |
532 | } | ||
533 | |||
534 | 1348 | void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion) | |
535 | // Set the current node to field type | ||
536 | 1348 | isFieldType = true; | |
537 | // Do the same for all template nodes | ||
538 | 1348 | const BaseDataTypeNode *baseType = baseDataType(); | |
539 | 1348 | const CustomDataTypeNode *customType = baseType->customDataType(); | |
540 |
6/6✓ Branch 0 taken 539 times.
✓ Branch 1 taken 809 times.
✓ Branch 3 taken 116 times.
✓ Branch 4 taken 423 times.
✓ Branch 5 taken 116 times.
✓ Branch 6 taken 1232 times.
|
1348 | if (customType != nullptr && customType->templateTypeLst()) |
541 |
4/6✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 116 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 154 times.
✓ Branch 12 taken 116 times.
|
270 | for (DataTypeNode *templateNode : customType->templateTypeLst()->dataTypes()) |
542 |
1/2✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
|
270 | templateNode->setFieldTypeRecursive(); |
543 | 1348 | } | |
544 | |||
545 | } // namespace spice::compiler | ||
546 |