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 | 19084 | const StmtLstNode *ASTNode::getNextOuterStmtLst() const { // NOLINT(*-no-recursion) | |
63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19084 times.
|
19084 | assert(parent != nullptr && "Could not find next outer statement list"); |
64 |
2/2✓ Branch 1 taken 12472 times.
✓ Branch 2 taken 6612 times.
|
31556 | return isStmtLst() ? 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 | 32 | CompileTimeValue GlobalVarDefNode::getCompileTimeValue() const { return constant->getCompileTimeValue(); } | |
76 | |||
77 | 806 | bool ForLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
78 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
79 | // we can assume that the loop itself will always return | ||
80 |
5/8✓ Branch 1 taken 806 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 805 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
|
806 | const bool loopConditionAlwaysTrue = condAssign->hasCompileTimeValue() && condAssign->getCompileTimeValue().boolValue; |
81 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 806 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
806 | return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
82 | } | ||
83 | |||
84 | 381 | bool WhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
85 | // If we have the guarantee that the loop condition is always true and the loop body returns on all control paths, | ||
86 | // we can assume that the loop itself will always return | ||
87 |
6/8✓ Branch 1 taken 381 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 377 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 1 times.
|
381 | const bool loopConditionAlwaysTrue = condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue; |
88 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 378 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
381 | return loopConditionAlwaysTrue && body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
89 | } | ||
90 | |||
91 | 9 | bool DoWhileLoopNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
92 | // Do-while loops will always be executed at least once. So if the body returns on all control paths, the loop will as well | ||
93 | 9 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
94 | } | ||
95 | |||
96 | 2339 | bool IfStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
97 | // If the condition always evaluates to 'true' the then block must return | ||
98 |
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 (condition->hasCompileTimeValue() && condition->getCompileTimeValue().boolValue) |
99 | 4 | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
100 | |||
101 | // If the condition always evaluates to 'false' the else block must return | ||
102 |
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 (condition->hasCompileTimeValue() && !condition->getCompileTimeValue().boolValue) |
103 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
8 | return elseStmt != nullptr && elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
104 | |||
105 | // If the condition does not always evaluate to 'true' or 'false' we need to check both branches | ||
106 |
4/4✓ Branch 1 taken 1665 times.
✓ Branch 2 taken 662 times.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 1636 times.
|
2356 | return thenBody->returnsOnAllControlPaths(doSetPredecessorsUnreachable) && elseStmt != nullptr && |
107 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
2356 | elseStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
108 | } | ||
109 | |||
110 | 31 | bool ElseStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { // NOLINT(misc-no-recursion) | |
111 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 21 times.
|
31 | if (isElseIf) |
112 | 10 | return ifStmt->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
113 | 21 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
114 | } | ||
115 | |||
116 | 8 | bool SwitchStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
117 | 23 | const auto pred = [=](const CaseBranchNode *node) { return node->returnsOnAllControlPaths(doSetPredecessorsUnreachable); }; | |
118 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | const bool allCaseBranchesReturn = std::ranges::all_of(caseBranches, pred); |
119 |
4/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
8 | const bool defaultBranchReturns = !defaultBranch || defaultBranch->returnsOnAllControlPaths(doSetPredecessorsUnreachable); |
120 |
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; |
121 | } | ||
122 | |||
123 | 23 | bool CaseBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
124 | 23 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
125 | } | ||
126 | |||
127 | 3 | bool DefaultBranchNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
128 | 3 | return body->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
129 | } | ||
130 | |||
131 | 11282 | bool StmtLstNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
132 | // An empty statement list does not return at all | ||
133 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 11254 times.
|
11282 | if (children.empty()) |
134 | 28 | return false; | |
135 | // A statement list returns on all control paths, if the one direct child statement returns on all control paths | ||
136 | 11254 | bool returnsOnAllControlPaths = false; | |
137 |
2/2✓ Branch 5 taken 22809 times.
✓ Branch 6 taken 11254 times.
|
34063 | for (ASTNode *child : children) { |
138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22809 times.
|
22809 | assert(child != nullptr); |
139 | |||
140 | // Prevent marking instructions as unreachable if doSetPredecessorsUnreachable is set to false | ||
141 |
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) |
142 | 5 | child->unreachable = true; | |
143 | |||
144 |
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)) |
145 | 6336 | returnsOnAllControlPaths = true; | |
146 | } | ||
147 | 11254 | return returnsOnAllControlPaths; | |
148 | } | ||
149 | |||
150 | 1304 | std::vector<const CompileTimeValue *> AttrLstNode::getAttrValuesByName(const std::string &key) const { | |
151 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1304 times.
|
1304 | assert(ATTR_CONFIGS.contains(key)); |
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 : attributes) { |
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 | 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 | 1304 | return attributeValues; | |
171 | ✗ | } | |
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 | 1998 | return std::ranges::any_of(attributes, [&](const AttrNode *attr) { return attr->key == key; }); | |
180 | } | ||
181 | |||
182 |
2/2✓ Branch 0 taken 597 times.
✓ Branch 1 taken 54 times.
|
651 | const CompileTimeValue *AttrNode::getValue() const { return value ? &value->compileTimeValue : nullptr; } |
183 | |||
184 | 607 | bool AssertStmtNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
185 | // If the expression, passed to the assert statement is always evaluated to false, the assert statement will never succeed | ||
186 |
6/8✓ Branch 1 taken 607 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 604 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
|
607 | return assignExpr->hasCompileTimeValue() && !assignExpr->getCompileTimeValue().boolValue; |
187 | } | ||
188 | |||
189 | 9852 | bool AssignExprNode::returnsOnAllControlPaths(bool *doSetPredecessorsUnreachable) const { | |
190 | // If it's a ternary, do the default thing | ||
191 |
2/2✓ Branch 0 taken 5530 times.
✓ Branch 1 taken 4322 times.
|
9852 | if (op == OP_NONE) |
192 | 5530 | return children.front()->returnsOnAllControlPaths(doSetPredecessorsUnreachable); | |
193 | |||
194 | // If it's a modification on the result variable, we technically return from the function, but at the end of the function. | ||
195 |
4/4✓ Branch 0 taken 4317 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 843 times.
✓ Branch 3 taken 3474 times.
|
4322 | const bool hasAtomicExpr = lhs->postfixUnaryExpr && lhs->postfixUnaryExpr->atomicExpr; |
196 |
6/6✓ Branch 0 taken 843 times.
✓ Branch 1 taken 3479 times.
✓ Branch 3 taken 358 times.
✓ Branch 4 taken 485 times.
✓ Branch 5 taken 358 times.
✓ Branch 6 taken 3964 times.
|
4322 | if (hasAtomicExpr && lhs->postfixUnaryExpr->atomicExpr->fqIdentifier == RETURN_VARIABLE_NAME) { |
197 | // If we assign the result variable, we technically return from the function, but at the end of the function. | ||
198 | // Therefore, the following code is not unreachable, but will be executed in any case. | ||
199 | 358 | *doSetPredecessorsUnreachable = false; | |
200 | 358 | return true; | |
201 | } | ||
202 | |||
203 | 3964 | return false; | |
204 | } | ||
205 | |||
206 | 7048 | bool TernaryExprNode::hasCompileTimeValue() const { | |
207 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7048 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7048 | const bool trueExprHasCompileTimeValue = !trueExpr || trueExpr->hasCompileTimeValue(); |
208 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7048 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7048 | const bool falseExprHasCompileTimeValue = !falseExpr || falseExpr->hasCompileTimeValue(); |
209 |
4/6✓ Branch 1 taken 237 times.
✓ Branch 2 taken 6811 times.
✓ Branch 3 taken 237 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 237 times.
✗ Branch 6 not taken.
|
7048 | return condition->hasCompileTimeValue() && trueExprHasCompileTimeValue && falseExprHasCompileTimeValue; |
210 | } | ||
211 | |||
212 | 79 | CompileTimeValue TernaryExprNode::getCompileTimeValue() const { | |
213 |
1/2✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
|
79 | if (children.size() == 1) |
214 | 79 | return children.front()->getCompileTimeValue(); | |
215 | |||
216 | // If the condition has no compile time value, we do not need to evaluate the true and false values | ||
217 | ✗ | if (!condition->hasCompileTimeValue()) | |
218 | ✗ | return {}; | |
219 | |||
220 | // Check if condition always evaluates to 'true' | ||
221 | ✗ | if (condition->getCompileTimeValue().boolValue) { | |
222 | ✗ | const LogicalOrExprNode *trueValue = isShortened ? condition : trueExpr; | |
223 | ✗ | return trueValue->getCompileTimeValue(); | |
224 | } else { | ||
225 | ✗ | return falseExpr->getCompileTimeValue(); | |
226 | } | ||
227 | } | ||
228 | |||
229 | 7048 | bool LogicalOrExprNode::hasCompileTimeValue() const { | |
230 | 14098 | return std::ranges::all_of(operands, [](const LogicalAndExprNode *node) { return node->hasCompileTimeValue(); }); | |
231 | } | ||
232 | |||
233 | 79 | CompileTimeValue LogicalOrExprNode::getCompileTimeValue() const { | |
234 |
2/2✓ Branch 1 taken 77 times.
✓ Branch 2 taken 2 times.
|
79 | if (children.size() == 1) |
235 | 77 | return children.front()->getCompileTimeValue(); | |
236 | |||
237 | // Check if one expression evaluates to 'true' | ||
238 |
2/2✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
|
6 | for (const LogicalAndExprNode *op : operands) { |
239 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
240 | // If one operand evaluates to 'true' the whole expression is 'true' | ||
241 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); |
242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (opCompileTimeValue.boolValue) |
243 | ✗ | return CompileTimeValue{.boolValue = true}; | |
244 | } | ||
245 | |||
246 | // Return 'false' | ||
247 | 2 | return CompileTimeValue{.boolValue = false}; | |
248 | } | ||
249 | |||
250 | 7054 | bool LogicalAndExprNode::hasCompileTimeValue() const { | |
251 | 14110 | return std::ranges::all_of(operands, [](const BitwiseOrExprNode *node) { return node->hasCompileTimeValue(); }); | |
252 | } | ||
253 | |||
254 | 81 | CompileTimeValue LogicalAndExprNode::getCompileTimeValue() const { | |
255 |
2/2✓ Branch 1 taken 79 times.
✓ Branch 2 taken 2 times.
|
81 | if (children.size() == 1) |
256 | 79 | return children.front()->getCompileTimeValue(); | |
257 | |||
258 | // Check if all expressions evaluate to 'true' | ||
259 |
1/2✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | for (const BitwiseOrExprNode *op : operands) { |
260 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | assert(op->hasCompileTimeValue()); |
261 | // If one operand evaluates to 'false' the whole expression is 'false' | ||
262 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const CompileTimeValue opCompileTimeValue = op->getCompileTimeValue(); |
263 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (!opCompileTimeValue.boolValue) |
264 | 2 | return CompileTimeValue{.boolValue = false}; | |
265 | } | ||
266 | |||
267 | // Return 'false' | ||
268 | ✗ | return CompileTimeValue{.boolValue = false}; | |
269 | } | ||
270 | |||
271 | 7060 | bool BitwiseOrExprNode::hasCompileTimeValue() const { | |
272 | 14120 | return std::ranges::all_of(operands, [](const BitwiseXorExprNode *node) { return node->hasCompileTimeValue(); }); | |
273 | } | ||
274 | |||
275 | 83 | CompileTimeValue BitwiseOrExprNode::getCompileTimeValue() const { | |
276 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
277 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
278 | |||
279 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
280 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
281 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
282 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
283 | ✗ | result.longValue |= opCompileTimeValue.longValue; | |
284 | } | ||
285 | |||
286 | ✗ | return result; | |
287 | } | ||
288 | |||
289 | 7060 | bool BitwiseXorExprNode::hasCompileTimeValue() const { | |
290 | 14120 | return std::ranges::all_of(operands, [](const BitwiseAndExprNode *node) { return node->hasCompileTimeValue(); }); | |
291 | } | ||
292 | |||
293 | 83 | CompileTimeValue BitwiseXorExprNode::getCompileTimeValue() const { | |
294 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
295 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
296 | |||
297 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
298 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
299 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
300 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
301 | ✗ | result.longValue ^= opCompileTimeValue.longValue; | |
302 | } | ||
303 | |||
304 | ✗ | return result; | |
305 | } | ||
306 | |||
307 | 7060 | bool BitwiseAndExprNode::hasCompileTimeValue() const { | |
308 | 14120 | return std::ranges::all_of(operands, [](const EqualityExprNode *node) { return node->hasCompileTimeValue(); }); | |
309 | } | ||
310 | |||
311 | 83 | CompileTimeValue BitwiseAndExprNode::getCompileTimeValue() const { | |
312 |
1/2✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
|
83 | if (children.size() == 1) |
313 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | return children.front()->getCompileTimeValue(); |
314 | |||
315 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
316 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
317 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
318 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
319 | ✗ | result.longValue &= opCompileTimeValue.longValue; | |
320 | } | ||
321 | |||
322 | ✗ | return result; | |
323 | } | ||
324 | |||
325 | 7060 | bool EqualityExprNode::hasCompileTimeValue() const { | |
326 | 14127 | return std::ranges::all_of(operands, [](const RelationalExprNode *node) { return node->hasCompileTimeValue(); }); | |
327 | } | ||
328 | |||
329 | 83 | CompileTimeValue EqualityExprNode::getCompileTimeValue() const { | |
330 |
2/2✓ Branch 1 taken 76 times.
✓ Branch 2 taken 7 times.
|
83 | if (children.size() == 1) |
331 |
1/2✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
76 | return children.front()->getCompileTimeValue(); |
332 | |||
333 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(); |
334 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(); |
335 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (op == OP_EQUAL) |
336 | 2 | return CompileTimeValue{.boolValue = op0Value.longValue == op1Value.longValue}; | |
337 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (op == OP_NOT_EQUAL) |
338 | 5 | return CompileTimeValue{.boolValue = op0Value.longValue != op1Value.longValue}; | |
339 | |||
340 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "EqualityExprNode::getCompileTimeValue()"); | |
341 | } | ||
342 | |||
343 | 7067 | bool RelationalExprNode::hasCompileTimeValue() const { | |
344 | 14135 | return std::ranges::all_of(operands, [](const ShiftExprNode *node) { return node->hasCompileTimeValue(); }); | |
345 | } | ||
346 | |||
347 | 90 | CompileTimeValue RelationalExprNode::getCompileTimeValue() const { | |
348 |
2/2✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
|
90 | if (children.size() == 1) |
349 |
1/2✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
|
89 | return children.front()->getCompileTimeValue(); |
350 | |||
351 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(); |
352 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(); |
353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (op == OP_LESS) |
354 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue < op1Value.longValue}; | |
355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (op == OP_GREATER) |
356 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue > op1Value.longValue}; | |
357 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (op == OP_LESS_EQUAL) |
358 | 1 | return CompileTimeValue{.boolValue = op0Value.longValue <= op1Value.longValue}; | |
359 | ✗ | if (op == OP_GREATER_EQUAL) | |
360 | ✗ | return CompileTimeValue{.boolValue = op0Value.longValue >= op1Value.longValue}; | |
361 | |||
362 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "RelationalExprNode::getCompileTimeValue()"); | |
363 | } | ||
364 | |||
365 | 7068 | bool ShiftExprNode::hasCompileTimeValue() const { | |
366 | 14136 | return std::ranges::all_of(operands, [](const AdditiveExprNode *node) { return node->hasCompileTimeValue(); }); | |
367 | } | ||
368 | |||
369 | 91 | CompileTimeValue ShiftExprNode::getCompileTimeValue() const { | |
370 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
371 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
372 | |||
373 | ✗ | const CompileTimeValue op0Value = operands.at(0)->getCompileTimeValue(); | |
374 | ✗ | const CompileTimeValue op1Value = operands.at(1)->getCompileTimeValue(); | |
375 | ✗ | if (op == OP_SHIFT_LEFT) | |
376 | ✗ | return CompileTimeValue{.longValue = op0Value.longValue << op1Value.longValue}; | |
377 | ✗ | if (op == OP_SHIFT_RIGHT) | |
378 | ✗ | return CompileTimeValue{.longValue = op0Value.longValue >> op1Value.longValue}; | |
379 | |||
380 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "ShiftExprNode::getCompileTimeValue()"); | |
381 | } | ||
382 | |||
383 | 7068 | bool AdditiveExprNode::hasCompileTimeValue() const { | |
384 | 14136 | return std::ranges::all_of(operands, [](const MultiplicativeExprNode *node) { return node->hasCompileTimeValue(); }); | |
385 | } | ||
386 | |||
387 | 91 | CompileTimeValue AdditiveExprNode::getCompileTimeValue() const { | |
388 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
389 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
390 | |||
391 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
392 | ✗ | OpQueue opQueueCopy = opQueue; | |
393 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
394 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
395 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
396 | ✗ | const AdditiveOp op = opQueueCopy.front().first; | |
397 | ✗ | opQueueCopy.pop(); | |
398 | ✗ | if (op == OP_PLUS) | |
399 | ✗ | result.longValue += opCompileTimeValue.longValue; | |
400 | ✗ | else if (op == OP_MINUS) | |
401 | ✗ | result.longValue -= opCompileTimeValue.longValue; | |
402 | else | ||
403 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "AdditiveExprNode::getCompileTimeValue()"); | |
404 | } | ||
405 | ✗ | return result; | |
406 | ✗ | } | |
407 | |||
408 | 7068 | bool MultiplicativeExprNode::hasCompileTimeValue() const { | |
409 | 14136 | return std::ranges::all_of(operands, [](const CastExprNode *node) { return node->hasCompileTimeValue(); }); | |
410 | } | ||
411 | |||
412 | 91 | CompileTimeValue MultiplicativeExprNode::getCompileTimeValue() const { | |
413 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
414 |
1/2✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | return children.front()->getCompileTimeValue(); |
415 | |||
416 | ✗ | CompileTimeValue result = operands.front()->getCompileTimeValue(); | |
417 | ✗ | OpQueue opQueueCopy = opQueue; | |
418 | ✗ | for (size_t i = 1; i < operands.size(); i++) { | |
419 | ✗ | assert(operands.at(i)->hasCompileTimeValue()); | |
420 | ✗ | const CompileTimeValue opCompileTimeValue = operands.at(i)->getCompileTimeValue(); | |
421 | ✗ | const MultiplicativeOp op = opQueueCopy.front().first; | |
422 | ✗ | opQueueCopy.pop(); | |
423 | ✗ | if (op == OP_MUL) { | |
424 | ✗ | result.longValue *= opCompileTimeValue.longValue; | |
425 | ✗ | } else if (op == OP_DIV) { | |
426 | ✗ | if (opCompileTimeValue.longValue == 0) | |
427 | ✗ | throw SemanticError(operands.at(i), DIVISION_BY_ZERO, "Dividing by zero is not allowed."); | |
428 | ✗ | result.longValue /= opCompileTimeValue.longValue; | |
429 | ✗ | } else if (op == OP_REM) { | |
430 | ✗ | result.longValue %= opCompileTimeValue.longValue; | |
431 | } else { | ||
432 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExprNode::getCompileTimeValue()"); | |
433 | } | ||
434 | } | ||
435 | ✗ | return result; | |
436 | ✗ | } | |
437 | |||
438 | 7068 | bool CastExprNode::hasCompileTimeValue() const { return prefixUnaryExpr->hasCompileTimeValue(); } | |
439 | |||
440 | 91 | CompileTimeValue CastExprNode::getCompileTimeValue() const { | |
441 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | if (children.size() == 1) |
442 | 91 | return children.front()->getCompileTimeValue(); | |
443 | ✗ | return prefixUnaryExpr->getCompileTimeValue(); | |
444 | } | ||
445 | |||
446 | 7317 | bool PrefixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
447 |
2/2✓ Branch 0 taken 7044 times.
✓ Branch 1 taken 273 times.
|
7317 | if (postfixUnaryExpr) |
448 | 7044 | return postfixUnaryExpr->hasCompileTimeValue(); | |
449 | |||
450 | 273 | const bool isOperatorSupported = | |
451 |
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; |
452 |
3/4✓ Branch 0 taken 249 times.
✓ Branch 1 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 249 times.
|
273 | return isOperatorSupported && prefixUnaryExpr->hasCompileTimeValue(); |
453 | } | ||
454 | |||
455 | 91 | CompileTimeValue PrefixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
456 |
1/2✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
|
91 | if (postfixUnaryExpr) |
457 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | return postfixUnaryExpr->getCompileTimeValue(); |
458 | |||
459 | ✗ | CompileTimeValue opValue = prefixUnaryExpr->getCompileTimeValue(); | |
460 | ✗ | if (op == OP_MINUS) | |
461 | ✗ | return CompileTimeValue{.longValue = -opValue.longValue}; | |
462 | ✗ | if (op == OP_PLUS_PLUS) | |
463 | ✗ | return CompileTimeValue{.longValue = ++opValue.longValue}; | |
464 | ✗ | if (op == OP_MINUS_MINUS) | |
465 | ✗ | return CompileTimeValue{.longValue = --opValue.longValue}; | |
466 | ✗ | if (op == OP_NOT) | |
467 | ✗ | return CompileTimeValue{.boolValue = !opValue.boolValue}; | |
468 | ✗ | if (op == OP_BITWISE_NOT) | |
469 | ✗ | return CompileTimeValue{.longValue = ~opValue.longValue}; | |
470 | |||
471 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExprNode::getCompileTimeValue()"); | |
472 | } | ||
473 | |||
474 | 7044 | bool PostfixUnaryExprNode::hasCompileTimeValue() const { // NOLINT(*-no-recursion) | |
475 |
2/2✓ Branch 0 taken 5524 times.
✓ Branch 1 taken 1520 times.
|
7044 | if (atomicExpr) |
476 | 5524 | return atomicExpr->hasCompileTimeValue(); | |
477 | |||
478 |
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; |
479 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1520 | return isOperatorSupported && postfixUnaryExpr->hasCompileTimeValue(); |
480 | } | ||
481 | |||
482 | 91 | CompileTimeValue PostfixUnaryExprNode::getCompileTimeValue() const { // NOLINT(*-no-recursion) | |
483 |
1/2✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
|
91 | if (atomicExpr) |
484 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | return atomicExpr->getCompileTimeValue(); |
485 | |||
486 | ✗ | CompileTimeValue opValue = postfixUnaryExpr->getCompileTimeValue(); | |
487 | ✗ | if (op == OP_PLUS_PLUS) | |
488 | ✗ | return CompileTimeValue{.longValue = opValue.longValue++}; | |
489 | ✗ | if (op == OP_MINUS_MINUS) | |
490 | ✗ | return CompileTimeValue{.longValue = opValue.longValue--}; | |
491 | |||
492 | ✗ | throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExprNode::getCompileTimeValue()"); | |
493 | } | ||
494 | |||
495 | /** | ||
496 | * Check if right above the closest assign expression ancestor is a statement node | ||
497 | * | ||
498 | * @return Has return value receiver or not | ||
499 | */ | ||
500 | 6376 | bool FctCallNode::hasReturnValueReceiver() const { | |
501 | 6376 | const ASTNode *node = parent; | |
502 |
2/2✓ Branch 1 taken 94813 times.
✓ Branch 2 taken 5117 times.
|
99930 | while (!node->isAssignExpr()) { |
503 | // As soon as we have a node with more than one child, we know that the return value is used | ||
504 |
2/2✓ Branch 1 taken 1259 times.
✓ Branch 2 taken 93554 times.
|
94813 | if (node->children.size() > 1) |
505 | 1259 | return true; | |
506 | 93554 | node = node->parent; | |
507 | } | ||
508 | // Also check the condition of the assign expression | ||
509 |
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->isExprStmt(); |
510 | } | ||
511 | |||
512 | 9 | bool LambdaFuncNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
513 | 9 | return body->returnsOnAllControlPaths(overrideUnreachable); | |
514 | } | ||
515 | |||
516 | 38 | bool LambdaProcNode::returnsOnAllControlPaths(bool *overrideUnreachable) const { | |
517 | 38 | return body->returnsOnAllControlPaths(overrideUnreachable); | |
518 | } | ||
519 | |||
520 | 1348 | void DataTypeNode::setFieldTypeRecursive() { // NOLINT(*-no-recursion) | |
521 | // Set the current node to field type | ||
522 | 1348 | isFieldType = true; | |
523 | // Do the same for all template nodes | ||
524 | 1348 | const CustomDataTypeNode *customType = baseDataType->customDataType; | |
525 |
4/4✓ Branch 0 taken 539 times.
✓ Branch 1 taken 809 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 423 times.
|
1348 | if (customType != nullptr && customType->templateTypeLst) |
526 |
2/2✓ Branch 5 taken 154 times.
✓ Branch 6 taken 116 times.
|
270 | for (DataTypeNode *templateNode : customType->templateTypeLst->dataTypes) |
527 |
1/2✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
|
154 | templateNode->setFieldTypeRecursive(); |
528 | 1348 | } | |
529 | |||
530 | } // namespace spice::compiler | ||
531 |