GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/ast/AST.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 515 676 76.2%
Functions: 160 257 62.3%
Branches: 774 1605 48.2%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file ast/AST.h
5 ///
6 /// @authors Nick Avramoussis, Richard Jones
7 ///
8 /// @brief Provides the definition for every abstract and concrete derived
9 /// class which represent a particular abstract syntax tree (AST) node
10 /// type.
11 ///
12 /// AST nodes represents a particular branch of a complete AST. Concrete
13 /// nodes can be thought of as leaf node types which hold semantic
14 /// information of a partial or complete statement or expression. A
15 /// string of AX can be fully represented by building the correct
16 /// AST structure. The AX grammar defined in axparser.y represents the
17 /// valid mapping of a tokenized string to AST nodes.
18 ///
19 /// AST node classes can either represent a "leaf-level" semantic
20 /// component of a given AX AST, or an abstract base type. The latter are
21 /// used by the parser and leaf-level AST nodes for storage of compatible
22 /// child nodes, and provide grouping of various nodes which share common
23 /// semantics. The main two types of abstract AST nodes are statements
24 /// and expressions.
25 ///
26
27 #ifndef OPENVDB_AX_AST_HAS_BEEN_INCLUDED
28 #define OPENVDB_AX_AST_HAS_BEEN_INCLUDED
29
30 #include "Tokens.h"
31
32 #include <openvdb/version.h>
33
34 #include <memory>
35 #include <utility>
36 #include <vector>
37
38 namespace openvdb {
39 OPENVDB_USE_VERSION_NAMESPACE
40 namespace OPENVDB_VERSION_NAME {
41
42 namespace ax {
43 namespace ast {
44
45 /// @brief Forward declaration of the base Abstract Syntax Tree type.
46 /// @note Not to be confused with ast::Node types, which are the base abstract
47 /// type for all AST nodes. Tree nodes are the highest possible concrete
48 /// node type (in terms of hierarchy) which represent a full AX file.
49 /// They are always returned from the parser.
50 struct Tree;
51
52 ////////////////////////////////////////////////////////////////////////
53 ////////////////////////////////////////////////////////////////////////
54
55 /// @details A reference list of all abstract and concrete AST nodes in
56 /// hierarchical order (non-linear)
57 /// Abstract nodes:
58 /// - Node
59 /// - Statement
60 /// - Expression
61 /// - Variable
62 /// - ValueBase
63 ///
64 /// Concrete nodes:
65 /// - Tree
66 /// - StatementList
67 /// - Block
68 /// - Loop
69 /// - Keyword
70 /// - ConditionalStatement
71 /// - CommaOperator
72 /// - BinaryOperator
73 /// - TernaryOperator
74 /// - AssignExpression
75 /// - Crement
76 /// - UnaryOperator
77 /// - Cast
78 /// - FunctionCall
79 /// - ArrayUnpack
80 /// - ArrayPack
81 /// - Attribute
82 /// - ExternalVariable
83 /// - DeclareLocal
84 /// - Local
85 /// - Value<double/float/int32_t/int16_t/int64_t/bool>
86 /// - Value<std::string>
87
88 ////////////////////////////////////////////////////////////////////////
89 ////////////////////////////////////////////////////////////////////////
90
91 /// @brief The base abstract node which determines the interface and required
92 /// methods for all derived concrete nodes which comprise a valid AST.
93 /// @note All AST nodes share a few common characteristics. All constructors
94 /// typically take pointers to the abstract (pure-virtual) node types
95 /// and assume ownership of this data on successful construction. Deep
96 /// copy methods propagate down through all children of a given AST node
97 /// but have the unique behavior of ensuring parent data is updated to
98 /// the newly created parent nodes. Due to this behavior and the fact
99 /// that most nodes store unique pointers to other nodes, we've omitted
100 /// comparison and equality operators.
101 struct Node
102 {
103 using Ptr = std::shared_ptr<Node>;
104 using UniquePtr = std::unique_ptr<Node>;
105
106 /// @brief An enumerated list of node types for all concrete node types.
107 /// These can be used for faster evaluation of a given concrete node
108 /// using the virtual function table via Node::nodetype() rather
109 /// than performing a dynamic_cast/calling Node::isType.
110 /// @note This is sometimes referred to as "manual RTTI". We use this
111 /// technique combine with single dispatch due to opting for CRTP on
112 /// the main visitor and no templated virtual method support in C++.
113 /// i.e. no way to double dispatch: visit<template T>(Visitor<T>*)
114 /// @note Abstract (pure-virtual) nodes are not listed here. Node::isType
115 /// should be used to determine if a node is of a given abstract
116 /// type.
117 enum NodeType {
118 TreeNode,
119 StatementListNode,
120 BlockNode,
121 ConditionalStatementNode,
122 CommaOperatorNode,
123 LoopNode,
124 KeywordNode,
125 AssignExpressionNode,
126 CrementNode,
127 UnaryOperatorNode,
128 BinaryOperatorNode,
129 TernaryOperatorNode,
130 CastNode,
131 AttributeNode,
132 FunctionCallNode,
133 ExternalVariableNode,
134 DeclareLocalNode,
135 ArrayPackNode,
136 ArrayUnpackNode,
137 LocalNode,
138 ValueBoolNode,
139 ValueInt16Node,
140 ValueInt32Node,
141 ValueInt64Node,
142 ValueFloatNode,
143 ValueDoubleNode,
144 ValueStrNode
145 };
146
147 112653 Node() = default;
148 virtual ~Node() = default;
149
150 /// @brief The deep copy method for a Node
151 /// @return A deep copy of the current node and all its children
152 virtual Node* copy() const = 0;
153
154 /// @name Name/Type
155 /// @{
156
157 /// @brief Virtual method for accessing node type information
158 /// @note This method should be used when querying a concrete nodes type.
159 /// @return Returns the enumerated node type from the NodeType list
160 virtual NodeType nodetype() const = 0;
161
162 /// @brief Virtual method for accessing node name information
163 /// @return Returns the node class name
164 virtual const char* nodename() const = 0;
165
166 /// @brief Virtual method for accessing node name information
167 /// @return Returns the short node class name
168 virtual const char* subname() const = 0;
169
170 /// @brief Virtual method for accessing a node's base class. Note that if
171 /// this is called explicitly on an instance of ast::Node (the top
172 /// most base class) a nullptr is returned. This is primarily used
173 /// by the Visitor to support hierarchical visits.
174 /// @return Returns the current node as its base class type.
175 virtual const Node* basetype() const { return nullptr; }
176
177 /// @brief Query whether or not this node is of a specific (derived) type.
178 /// This method should be used to check if a node is of a particular
179 /// abstract type. When checking concrete types, it's generally
180 /// more efficient to check the return value of Node::nodetype()
181 /// @tparam NodeT The node type to query against.
182 /// @return True if this node is of the given type, false otherwise.
183 template <typename NodeT>
184 inline bool isType() const {
185
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10212 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12091 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
22305 return dynamic_cast<const NodeT*>(this);
186 }
187
188 /// @}
189
190 /// @name Child Queries
191 /// @{
192
193 /// @brief Virtual method for accessing child information. Returns the
194 /// number of children a given AST node owns.
195 /// @return The number of children this node owns.
196 virtual size_t children() const = 0;
197
198 /// @brief Virtual method for accessing child information. Returns a const
199 /// pointer to a child node at the given index. If the index is out
200 /// of range, a nullptr is returned.
201 /// @note This may still return a nullptr even if the given index is valid
202 /// if the child node has not been created.
203 /// @param index The child index to query
204 /// @return A Pointer to the child node, or a nullptr if none exists.
205 virtual const Node* child(const size_t index) const = 0;
206
207 /// @brief Returns the child index of this node in relation to its parent,
208 /// or -1 if no valid index is found (usually representing the top
209 /// most node (i.e. Tree)
210 /// @return The child index of this node
211 4565 inline int64_t childidx() const
212 {
213 const Node* p = this->parent();
214 4565 if (!p) return -1;
215 size_t i = 0;
216 4565 const size_t count = p->children();
217
1/2
✓ Branch 0 taken 22607 times.
✗ Branch 1 not taken.
22607 for (; i < count; ++i) {
218
2/2
✓ Branch 1 taken 18042 times.
✓ Branch 2 taken 4565 times.
22607 if (p->child(i) == this) break;
219 }
220
1/2
✓ Branch 0 taken 4565 times.
✗ Branch 1 not taken.
4565 if (i == count) return -1;
221 4565 return static_cast<int64_t>(i);
222 }
223
224 /// @}
225
226 /// @name Replacement
227 /// @{
228
229 /// @brief In place replacement. Attempts to replace this node at its
230 /// specific location within its Abstract Syntax Tree. On a
231 /// successful replacement, this node is destroyed, the provided
232 /// node is inserted in its place and ownership is transferred to the
233 /// parent node. No further calls to this node can be made on
234 /// successful replacements.
235 /// @note A replacement will fail if this node is the top most node within
236 /// an AST hierarchy or if the provided node type is not a
237 /// compatible type for the required abstract storage. For example,
238 /// if this node is an Attribute being held on a BinaryOperator,
239 /// only concrete nodes derived from an Expression can be used as a
240 /// replacement.
241 /// @note This method will dynamic_cast the provided node to check to see
242 /// if it's a compatible type.
243 /// @param node The node to insert on a successful replacement.
244 /// @return True if the replacement was successful, resulting in destruction
245 /// of this class and ownership transferal of the provided node.
246 /// False otherwise, where this and the provided node are unchanged.
247 7 inline bool replace(Node* node)
248 {
249 7 const int64_t idx = this->childidx();
250
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (idx == -1) return false; // avoid second vcall
251 7 return this->parent()->replacechild(idx, node);
252 }
253
254 /// @brief Virtual method that attempted to replace a child at a given
255 /// index with a provided node type.
256 /// @note See Node::replace for a more detailed description
257 /// @param index The child index where a replacement should be attempted
258 /// @param node The node to insert on a successful replacement.
259 /// @return True if the replacement was successful, false otherwise
260 inline virtual bool replacechild(const size_t index, Node* node);
261
262 /// @}
263
264 /// @name Parent
265 /// @{
266
267 /// @brief Access a const pointer to this nodes parent
268 /// @note Can be a nullptr if this is the top most node in an AST (usually
269 /// a Tree)
270 /// @return A const pointer to this node's parent node
271
4/4
✓ Branch 0 taken 74118 times.
✓ Branch 1 taken 19232 times.
✓ Branch 2 taken 215360 times.
✓ Branch 3 taken 50855 times.
403056 inline const Node* parent() const { return mParent; }
272
273 /// @brief Set this node's parent. This is used during construction of an
274 /// AST and should not be used. @todo Make this private.
275 /// @param parent The parent to set
276 144533 inline void setParent(Node* parent) {
277 #ifndef NDEBUG
278 bool hasChild = false;
279
2/2
✓ Branch 1 taken 556939 times.
✓ Branch 2 taken 144533 times.
701472 for (size_t i = 0; i < parent->children(); ++i)
280 556939 hasChild |= parent->child(i) == this;
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144533 times.
144533 assert(hasChild);
282 #endif
283 144533 mParent = parent;
284 144533 }
285
286 private:
287 /// @brief Access a non const pointer to this nodes parent. Used by
288 /// replacement methods.
289 /// @note Can be a nullptr if this is the top most node in an AST (usually
290 /// a Tree)
291 /// @return A non-const pointer to this nodes parent node
292 7 inline Node* parent() { return mParent; }
293
294 /// @}
295
296 Node* mParent = nullptr;
297 };
298
299 inline bool Node::replacechild(const size_t, Node*) { return false; }
300
301
302 ////////////////////////////////////////////////////////////////////////
303 ////////////////////////////////////////////////////////////////////////
304
305 /// Abstract (pure-virtual) AST nodes
306
307 /// @brief Statements are anything that can make up a line, i.e. everything
308 /// in between semicolons. Likewise to their base ast::Node class,
309 /// currently every concrete AST node is either directly or indirectly
310 /// a derived statement type. They hold no class data.
311 struct Statement : public Node
312 {
313 using UniquePtr = std::unique_ptr<Statement>;
314 ~Statement() override = default;
315 virtual Statement* copy() const override = 0;
316
19/52
✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1189 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 71 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 84 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 72 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 42 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 145 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 85 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 115 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 138 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 98 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 116 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 99 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 6 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 84 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 224 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 14 times.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 3 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
3602 const Node* basetype() const override { return this; }
317 };
318
319 /// @brief Expressions are comprised of full or potentially partial parts of a
320 /// full statement that may not necessary make up an entire valid
321 /// statement on their own. For example, while a Binary Operator such as
322 /// "3 + 5;"" is a valid statement on its own, the full statement
323 /// "3 + 5 + 6;" must be broken down into two expressions which together
324 /// form the statement as well as determining precedence.
325 struct Expression : public Statement
326 {
327 using UniquePtr = std::unique_ptr<Expression>;
328 ~Expression() override = default;
329 virtual Expression* copy() const override = 0;
330
21/80
✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1189 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 71 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 82 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 72 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 42 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 144 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 84 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 115 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 138 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 98 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✓ Branch 42 taken 1 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 1 times.
✗ Branch 45 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 2 times.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✓ Branch 54 taken 1 times.
✗ Branch 55 not taken.
✓ Branch 56 taken 1 times.
✗ Branch 57 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✓ Branch 64 taken 3 times.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✓ Branch 76 taken 3 times.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
3066 const Statement* basetype() const override { return this; }
331 };
332
333 /// @brief Variables are a base type for Locals, Attributes and
334 /// ExternalVariables. Unlike other abstract types, they also consolidate
335 /// data for the derived types.
336 struct Variable : public Expression
337 {
338 using UniquePtr = std::unique_ptr<Variable>;
339
340 Variable(const std::string& name)
341
2/4
✓ Branch 1 taken 11416 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
21573 : Expression(), mName(name) {}
342 Variable(const Variable& other)
343
1/2
✓ Branch 1 taken 4701 times.
✗ Branch 2 not taken.
4701 : Expression(), mName(other.mName) {}
344 35631 ~Variable() override = default;
345
346 virtual Variable* copy() const override = 0;
347
5/18
✓ Branch 0 taken 1188 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
1195 const Expression* basetype() const override { return this; }
348 //
349 717744 size_t children() const override { return 0; }
350 const Node* child(const size_t) const override { return nullptr; }
351 //
352
8/10
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5077 times.
✓ Branch 3 taken 15230 times.
✓ Branch 4 taken 39326 times.
✓ Branch 5 taken 1425 times.
✓ Branch 6 taken 5919 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30583 times.
✓ Branch 9 taken 82719 times.
273978 inline const std::string& name() const { return mName; }
353
354 private:
355 const std::string mName;
356 };
357
358 /// @brief ValueBases are a base class for anything that holds a value (literal).
359 /// Derived classes store the actual typed values
360 struct ValueBase : public Expression
361 {
362 using UniquePtr = std::unique_ptr<ValueBase>;
363 ~ValueBase() override = default;
364 virtual Expression* copy() const override = 0;
365
12/42
✓ Branch 0 taken 876 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 30 taken 1 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 2 times.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
889 const Expression* basetype() const override { return this; }
366 //
367 1128808 size_t children() const override { return 0; }
368 const Node* child(const size_t) const override { return nullptr; }
369 };
370
371
372 ////////////////////////////////////////////////////////////////////////
373 ////////////////////////////////////////////////////////////////////////
374
375 /// Concrete AST nodes
376
377 /// @brief A StatementList is derived from a Statement and comprises of
378 /// combinations of multiple statements. This could represent either
379 /// a list of statements of different types but in practice will likely
380 /// represent a ',' separated list of the same type i.e.
381 /// 'int i = 1, j = 1;'.
382 /// @note Statements held by the list are guaranteed to be valid (non null).
383 /// nullptrs added to the list are implicitly dropped.
384 /// @todo Consider combination with Block
385 struct StatementList : public Statement
386 {
387 using UniquePtr = std::unique_ptr<StatementList>;
388
389 /// @brief Construct a new StatementList with an empty list
390 StatementList() : mList() {}
391 /// @brief Construct a new StatementList with a single statement,
392 /// transferring ownership of the statement to the statement list
393 /// and updating parent data on the statement. If the statement is a
394 /// nullptr, it is ignored.
395 /// @param statement The statement to construct from
396 347 StatementList(Statement* statement)
397
1/2
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
347 : mList() {
398
1/2
✓ Branch 1 taken 347 times.
✗ Branch 2 not taken.
347 this->addStatement(statement);
399 347 }
400 /// @brief Construct a new StatementList from a vector of statements,
401 /// transferring ownership of all valid statements to the statement
402 /// list and updating parent data on the statement. Only valid (non
403 /// null) statements are added to the statement list.
404 /// @param statements The vector of statements to construct from
405 7 StatementList(const std::vector<Statement*>& statements)
406 7 : mList() {
407
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7 times.
27 for (Statement* statement : statements) {
408
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 this->addStatement(statement);
409 }
410 7 }
411 /// @brief Deep copy constructor for a StatementList, performing a deep
412 /// copy on every held statement, ensuring parent information is
413 /// updated.
414 /// @param other A const reference to another statement list to deep copy
415 116 StatementList(const StatementList& other) : mList() {
416
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 116 times.
348 for (const Statement::UniquePtr& stmnt : other.mList) {
417
2/4
✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 232 times.
✗ Branch 5 not taken.
232 this->addStatement(stmnt->copy());
418 }
419 116 }
420 940 ~StatementList() override = default;
421
422 /// @copybrief Node::copy()
423
1/2
✓ Branch 2 taken 116 times.
✗ Branch 3 not taken.
116 StatementList* copy() const override { return new StatementList(*this); }
424 /// @copybrief Node::nodetype()
425 5568 NodeType nodetype() const override { return Node::StatementListNode; }
426 /// @copybrief Node::nodename()
427 const char* nodename() const override { return "statement list"; }
428 /// @copybrief Node::subname()
429 const char* subname() const override { return "stml"; }
430 /// @copybrief Node::basetype()
431
1/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 const Statement* basetype() const override { return this; }
432
433 /// @copybrief Node::children()
434 2426 size_t children() const override final { return this->size(); }
435 /// @copybrief Node::child()
436
1/2
✓ Branch 0 taken 1470 times.
✗ Branch 1 not taken.
1470 const Statement* child(const size_t i) const override final {
437
8/22
✓ Branch 0 taken 2364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 475 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 509 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 469 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1629 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2248 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 3408 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
11107 if (i >= mList.size()) return nullptr;
438 11095 return mList[i].get();
439 }
440 /// @copybrief Node::replacechild()
441 inline bool replacechild(const size_t i, Node* node) override final {
442 if (mList.size() <= i) return false;
443 Expression* expr = dynamic_cast<Expression*>(node);
444 if (!expr) return false;
445 mList[i].reset(expr);
446 mList[i]->setParent(this);
447 return true;
448 }
449
450 /// @brief Alias for StatementList::children
451 inline size_t size() const { return mList.size(); }
452 /// @brief Adds a statement to this statement list, transferring ownership to the
453 /// statement list and updating parent data on the statement. If the
454 /// statement is a nullptr, it is ignored.
455 958 inline void addStatement(Statement* stmnt) {
456
1/2
✓ Branch 0 taken 958 times.
✗ Branch 1 not taken.
958 if (stmnt) {
457 958 mList.emplace_back(stmnt);
458 958 stmnt->setParent(this);
459 }
460 958 }
461 private:
462 std::vector<Statement::UniquePtr> mList;
463 };
464
465 /// @brief A Block node represents a scoped list of statements. It may comprise
466 /// of 0 or more statements, and specifically indicates that a new scope
467 /// is activated, typically represented by curly braces. Note that a
468 /// block does not alway have to be encapsulated by curly braces, but
469 /// always represents a new scope.
470 /// @note Statements held by the block are guaranteed to be valid (non null).
471 /// nullptrs added to the block are implicitly dropped.
472 /// @note While closely linked, it's important to differentiate between this
473 /// class and an llvm::BasicBlock.
474 /// @todo Consider combination with StatementList
475 struct Block : public Statement
476 {
477 using UniquePtr = std::unique_ptr<Block>;
478
479 /// @brief Construct a new Block with an empty list
480
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 3801 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3895 Block() : mList() {}
481 /// @brief Construct a new Block with a single statement, transferring
482 /// ownership of the statement to the block and updating parent
483 /// data on the statement. If the statement is a nullptr, it is
484 /// ignored.
485 /// @param statement The statement to construct from
486 33 Block(Statement* statement)
487
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 : mList() {
488
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 this->addStatement(statement);
489 33 }
490 /// @brief Construct a new Block from a vector of statements, transferring
491 /// ownership of all valid statements to the block and updating
492 /// parent data on the statement. Only valid (non null) statements
493 /// are added to the block.
494 /// @param statements The vector of statements to construct from
495 Block(const std::vector<Statement*>& statements)
496 : mList() {
497 for (Statement* statement : statements) {
498 this->addStatement(statement);
499 }
500 }
501 /// @brief Deep copy constructor for a Block, performing a deep copy on
502 /// every held statement, ensuring parent information is updated.
503 /// @param other A const reference to another block to deep copy
504 1072 Block(const Block& other) : mList() {
505
2/2
✓ Branch 0 taken 7543 times.
✓ Branch 1 taken 1072 times.
8615 for (const Statement::UniquePtr& stmnt : other.mList) {
506
2/4
✓ Branch 1 taken 7543 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7543 times.
✗ Branch 5 not taken.
7543 this->addStatement(stmnt->copy());
507 }
508 1072 }
509 10166 ~Block() override = default;
510
511 /// @copybrief Node::copy()
512
1/2
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
288 Block* copy() const override final { return new Block(*this); }
513 /// @copybrief Node::nodetype()
514 98423 NodeType nodetype() const override { return Node::BlockNode; }
515 /// @copybrief Node::nodename()
516 const char* nodename() const override { return "scoped block"; }
517 /// @copybrief Node::subname()
518 const char* subname() const override { return "blk"; }
519 /// @copybrief Node::basetype()
520
1/4
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
224 const Statement* basetype() const override { return this; }
521
522 /// @copybrief Node::children()
523 239575 size_t children() const override final { return this->size(); }
524 /// @copybrief Node::child()
525
1/2
✓ Branch 0 taken 234438 times.
✗ Branch 1 not taken.
234438 const Statement* child(const size_t i) const override final {
526
14/32
✓ Branch 0 taken 23628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15028 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15013 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14947 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 51815 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 80886 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 65 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 230248 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 234438 times.
✗ Branch 31 not taken.
666073 if (i >= mList.size()) return nullptr;
527 666073 return mList[i].get();
528 }
529 /// @copybrief Node::replacechild()
530 inline bool replacechild(const size_t i, Node* node) override final {
531 if (mList.size() <= i) return false;
532 Expression* expr = dynamic_cast<Expression*>(node);
533 if (!expr) return false;
534 mList[i].reset(expr);
535 mList[i]->setParent(this);
536 return true;
537 }
538
539 /// @brief Alias for Block::children
540 inline size_t size() const { return mList.size(); }
541 /// @brief Adds a statement to this block, transferring ownership to the
542 /// block and updating parent data on the statement. If the
543 /// statement is a nullptr, it is ignored.
544 24568 inline void addStatement(Statement* stmnt) {
545
2/2
✓ Branch 0 taken 24433 times.
✓ Branch 1 taken 135 times.
24568 if (stmnt) {
546 24433 mList.emplace_back(stmnt);
547 24433 stmnt->setParent(this);
548 }
549 24568 }
550 private:
551 std::vector<Statement::UniquePtr> mList;
552 };
553
554 /// @brief A Tree is the highest concrete (non-abstract) node in the entire AX
555 /// AST hierarchy. It represents an entire conversion of a valid AX
556 /// string.
557 /// @note A tree is the only node type which has typedefs for use as a shared
558 /// pointer. All other nodes are expected to be handled through unique
559 /// pointers to infer ownership.
560 /// @todo Replace block with StatementList
561 struct Tree : public Node
562 {
563 using Ptr = std::shared_ptr<Tree>;
564 using ConstPtr = std::shared_ptr<const Tree>;
565 using UniquePtr = std::unique_ptr<Tree>;
566
567 /// @brief Construct a new Tree from a given Block, transferring ownership
568 /// of the Block to the tree and updating parent data on the Block.
569 /// @note The provided Block must be a valid pointer (non-null)
570 /// @param block The Block to construct from
571 2979 Tree(Block* block = new Block())
572
1/2
✓ Branch 1 taken 2979 times.
✗ Branch 2 not taken.
2979 : mBlock(block) {
573
1/2
✓ Branch 1 taken 2979 times.
✗ Branch 2 not taken.
2979 mBlock->setParent(this);
574 2979 }
575 /// @brief Deep copy constructor for a Tree, performing a deep copy on
576 /// the held Block, ensuring parent information is updated.
577 /// @param other A const reference to another Tree to deep copy
578 784 Tree(const Tree& other)
579
1/2
✓ Branch 2 taken 784 times.
✗ Branch 3 not taken.
784 : mBlock(new Block(*other.mBlock)) {
580
1/2
✓ Branch 1 taken 784 times.
✗ Branch 2 not taken.
784 mBlock->setParent(this);
581 784 }
582
2/6
✓ Branch 0 taken 3763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
15048 ~Tree() override = default;
583
584 /// @copybrief Node::copy()
585
1/2
✓ Branch 2 taken 784 times.
✗ Branch 3 not taken.
784 Tree* copy() const override final { return new Tree(*this); }
586 /// @copybrief Node::nodetype()
587 91420 NodeType nodetype() const override { return Node::TreeNode; }
588 /// @copybrief Node::nodename()
589 const char* nodename() const override { return "tree"; }
590 /// @copybrief Node::subname()
591 const char* subname() const override { return "tree"; }
592 /// @copybrief Node::basetype()
593 const Node* basetype() const override { return this; }
594
595 /// @copybrief Node::children()
596 9383 size_t children() const override final { return 1; }
597 /// @copybrief Node::child()
598 7477 const Block* child(const size_t i) const override final {
599
1/2
✓ Branch 0 taken 17730 times.
✗ Branch 1 not taken.
17730 if (i == 0) return mBlock.get();
600 return nullptr;
601 }
602 private:
603 Block::UniquePtr mBlock;
604 };
605
606 struct CommaOperator : public Expression
607 {
608 using UniquePtr = std::unique_ptr<CommaOperator>;
609
610 /// @brief Construct a new CommaOperator with an expr set
611 CommaOperator() : mExpressions() {}
612 /// @brief Construct a new CommaOperator with a single expression,
613 /// transferring ownership of the expression to the CommaOperator
614 /// and updating parent data on the expression. If the expression is
615 /// a nullptr, it is ignored.
616 /// @param expression The Expression to construct from
617 CommaOperator(Expression* expression)
618 : mExpressions() {
619 this->append(expression);
620 }
621 /// @brief Construct a new CommaOperator from a vector of expression,
622 /// transferring ownership of all valid expression to the
623 /// CommaOperator and updating parent data on the statement. Only
624 /// valid (non null) expression are added to the block.
625 /// @param expressions The vector of expressions to construct from
626 337 CommaOperator(const std::vector<Expression*>& expressions)
627
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 : mExpressions() {
628
1/2
✓ Branch 1 taken 337 times.
✗ Branch 2 not taken.
337 mExpressions.reserve(expressions.size());
629
2/2
✓ Branch 0 taken 935 times.
✓ Branch 1 taken 337 times.
1272 for (Expression* expression : expressions) {
630
1/2
✓ Branch 1 taken 935 times.
✗ Branch 2 not taken.
935 this->append(expression);
631 }
632 337 }
633 /// @brief Deep copy constructor for an CommaOperator, performing a deep
634 /// copy on every held expression, ensuring parent information is
635 /// updated.
636 /// @param other A const reference to another CommaOperator to deep copy
637 88 CommaOperator(const CommaOperator& other)
638
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 : mExpressions() {
639
1/2
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
88 mExpressions.reserve(other.mExpressions.size());
640
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 88 times.
312 for (const Expression::UniquePtr& expr : other.mExpressions) {
641
2/4
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 224 times.
✗ Branch 5 not taken.
224 this->append(expr->copy());
642 }
643 88 }
644 850 ~CommaOperator() override = default;
645
646 /// @copybrief Node::copy()
647 88 CommaOperator* copy() const override final {
648
1/2
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
88 return new CommaOperator(*this);
649 }
650 /// @copybrief Node::nodetype()
651 6422 NodeType nodetype() const override { return Node::CommaOperatorNode; }
652 /// @copybrief Node::nodename()
653 const char* nodename() const override { return "comma"; }
654 /// @copybrief Node::subname()
655 const char* subname() const override { return "comma"; }
656 /// @copybrief Node::basetype()
657
1/6
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
98 const Expression* basetype() const override { return this; }
658
659 /// @copybrief Node::children()
660 3715 size_t children() const override final { return this->size(); }
661 /// @copybrief Node::child()
662
1/2
✓ Branch 0 taken 2559 times.
✗ Branch 1 not taken.
2559 const Expression* child(const size_t i) const override final {
663
8/22
✓ Branch 0 taken 3495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 688 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 750 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 688 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1568 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2652 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 2956 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 116 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
12913 if (i >= mExpressions.size()) return nullptr;
664 12913 return mExpressions[i].get();
665 }
666 /// @copybrief Node::replacechild()
667 inline bool replacechild(const size_t i, Node* node) override final {
668 if (mExpressions.size() <= i) return false;
669 Expression* expr = dynamic_cast<Expression*>(node);
670 mExpressions[i].reset(expr);
671 mExpressions[i]->setParent(this);
672 return true;
673 }
674
675 /// @brief Alias for CommaOperator::children
676 inline size_t size() const { return mExpressions.size(); }
677 /// @brief Query whether this Expression list holds any valid expressions
678 /// @return True if this node if empty, false otherwise
679 inline bool empty() const { return mExpressions.empty(); }
680 /// @brief Append an expression to this CommaOperator, transferring
681 /// ownership to the CommaOperator and updating parent data on the
682 /// expression. If the expression is a nullptr, it is ignored.
683 1159 inline void append(Expression* expr) {
684
1/2
✓ Branch 0 taken 1159 times.
✗ Branch 1 not taken.
1159 if (expr) {
685 1159 mExpressions.emplace_back(expr);
686 1159 expr->setParent(this);
687 }
688 1159 }
689 private:
690 std::vector<Expression::UniquePtr> mExpressions;
691 };
692
693 /// @brief Loops represent for, while and do-while loop constructs.
694 /// These all consist of a condition - evaluated to determine if loop
695 /// iteration should continue, and a body which is the logic to be
696 /// repeated. For loops also have initial statements which are evaluated
697 /// prior to loop execution (at loop scope) and commonly used to
698 /// set up iterators, and iteration expressions which are evaluated
699 /// between iterations after the body and before the condition.
700 /// Both conditions and initial statements can be declarations or
701 /// expressions, so are Statements, and iteration expressions can
702 /// consist of multiple expressions. The loop body is a Block defining
703 /// its own scope (encapsulated by initial statement scope for for-loops).
704 /// @note Only for-loops should have initial statements and/or iteration
705 /// expressions. Also for-loops allow empty conditions to be given by
706 /// the user, this is replaced with a 'true' expression in the parser.
707 struct Loop : public Statement
708 {
709 using UniquePtr = std::unique_ptr<Loop>;
710
711 /// @brief Construct a new Loop with the type defined by a
712 /// tokens::LoopToken, a condition Statement, a Block representing
713 /// the body and for for-loops an optional initial Statement and
714 /// iteration Expression. Ownership of all arguments is
715 /// transferred to the Loop. All arguments have their parent data
716 /// updated.
717 /// @param loopType The type of loop - for, while or do-while.
718 /// @param condition The condition Statement to determine loop repetition
719 /// @param body The Block to be repeated
720 /// @param init The (optional) for-loop initial Statement.
721 /// @param iter The (optional) for-loop iteration Expression.
722 360 Loop(const tokens::LoopToken loopType,
723 Statement* condition,
724 Block* body,
725 Statement* init = nullptr,
726 Expression* iter = nullptr)
727 360 : mLoopType(loopType)
728 , mConditional(condition)
729 , mBody(body)
730 , mInitial(init)
731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 , mIteration(iter) {
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 assert(mConditional);
733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 360 times.
360 assert(mBody);
734
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 mConditional->setParent(this);
735
1/2
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
360 mBody->setParent(this);
736
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 175 times.
360 if (mInitial) {
737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 assert(mLoopType == tokens::LoopToken::FOR);
738
1/2
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
185 mInitial->setParent(this);
739 }
740
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 170 times.
360 if (mIteration) {
741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 assert(mLoopType == tokens::LoopToken::FOR);
742
1/2
✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
190 mIteration->setParent(this);
743 }
744 360 }
745 /// @brief Deep copy constructor for an Loop, performing a deep copy on the
746 /// condition, body and initial Statement/iteration Expression
747 /// if they exist, ensuring parent information is updated.
748 /// @param other A const reference to another Loop to deep copy
749 84 Loop(const Loop& other)
750 84 : mLoopType(other.mLoopType)
751 84 , mConditional(other.mConditional->copy())
752 , mBody(other.mBody->copy())
753
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 , mInitial(other.hasInit() ? other.mInitial->copy() : nullptr)
754
6/8
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 50 times.
✓ Branch 7 taken 34 times.
✓ Branch 9 taken 50 times.
✗ Branch 10 not taken.
132 , mIteration(other.hasIter() ? other.mIteration->copy() : nullptr) {
755
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 mConditional->setParent(this);
756
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 mBody->setParent(this);
757
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 36 times.
84 if (mInitial) {
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 assert(mLoopType == tokens::LoopToken::FOR);
759
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 mInitial->setParent(this);
760 }
761
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 34 times.
84 if (mIteration) {
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 assert(mLoopType == tokens::LoopToken::FOR);
763
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 mIteration->setParent(this);
764 }
765 84 }
766
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 204 times.
1776 ~Loop() override = default;
767
768 /// @copybrief Node::copy()
769
1/2
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
84 Loop* copy() const override final { return new Loop(*this); }
770 /// @copybrief Node::nodetype()
771 22193 NodeType nodetype() const override { return Node::LoopNode; }
772 /// @copybrief Node::nodename()
773 const char* nodename() const override { return "loop"; }
774 /// @copybrief Node::subname()
775 const char* subname() const override { return "loop"; }
776 /// @copybrief Node::basetype()
777
1/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
84 const Statement* basetype() const override { return this; }
778
779 /// @copybrief Node::children()
780 6865 size_t children() const override final { return 4; }
781 /// @copybrief Node::child()
782 5572 const Statement* child(const size_t i) const override final {
783
12/24
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 492 times.
✓ Branch 4 taken 248 times.
✓ Branch 5 taken 744 times.
✓ Branch 6 taken 164 times.
✓ Branch 7 taken 492 times.
✓ Branch 8 taken 560 times.
✓ Branch 9 taken 1680 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1477 times.
✓ Branch 23 taken 4095 times.
10452 if (i == 0) return mConditional.get();
784
12/24
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 328 times.
✓ Branch 4 taken 248 times.
✓ Branch 5 taken 496 times.
✓ Branch 6 taken 164 times.
✓ Branch 7 taken 328 times.
✓ Branch 8 taken 560 times.
✓ Branch 9 taken 1120 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1365 times.
✓ Branch 23 taken 2730 times.
7755 if (i == 1) return mBody.get();
785
12/24
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 164 times.
✓ Branch 4 taken 248 times.
✓ Branch 5 taken 248 times.
✓ Branch 6 taken 164 times.
✓ Branch 7 taken 164 times.
✓ Branch 8 taken 560 times.
✓ Branch 9 taken 560 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1369 times.
✓ Branch 23 taken 1361 times.
5170 if (i == 2) return mInitial.get();
786
6/24
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 248 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 164 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 560 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1361 times.
✗ Branch 23 not taken.
2581 if (i == 3) return mIteration.get();
787 return nullptr;
788 }
789 /// @copybrief Node::replacechild()
790 inline bool replacechild(const size_t i, Node* node) override final
791 {
792 if (i == 0 || i == 2) {
793 Statement* stmt = dynamic_cast<Statement*>(node);
794 if (!stmt) return false;
795 if (i == 0) {
796 mConditional.reset(stmt);
797 mConditional->setParent(this);
798 }
799 else {
800 mInitial.reset(stmt);
801 mInitial->setParent(this);
802 }
803 return true;
804 }
805 else if (i == 1) {
806 Block* blk = dynamic_cast<Block*>(node);
807 if (!blk) return false;
808 mBody.reset(blk);
809 mBody->setParent(this);
810 return true;
811 }
812 else if (i == 3) {
813 Expression* expr = dynamic_cast<Expression*>(node);
814 if (!expr) return false;
815 mIteration.reset(expr);
816 mIteration->setParent(expr);
817 return true;
818 }
819 return false;
820 }
821
822 /// @brief Query the type of loop held on this node.
823 /// @return The loop type as a tokens::LoopToken
824
4/4
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 662 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
798 inline tokens::LoopToken loopType() const { return mLoopType; }
825 /// @brief Query if this Loop has a valid initial statement
826 /// @return True if a valid initial statement exists, false otherwise
827 inline bool hasInit() const { return static_cast<bool>(this->initial()); }
828 /// @brief Query if this Loop has a valid iteration expression list
829 /// @return True if a valid iteration list exists, false otherwise
830 inline bool hasIter() const { return static_cast<bool>(this->iteration()); }
831 /// @brief Access a const pointer to the Loop condition as an abstract
832 /// statement.
833 /// @return A const pointer to the condition as a statement
834 const Statement* condition() const { return mConditional.get(); }
835 /// @brief Access a const pointer to the Loop body as a Block.
836 /// @return A const pointer to the body Block
837 const Block* body() const { return mBody.get(); }
838 /// @brief Access a const pointer to the Loop initial statement as an
839 /// abstract statement.
840 /// @return A const pointer to the initial statement as a statement
841 const Statement* initial() const { return mInitial.get(); }
842 /// @brief Access a const pointer to the Loop iteration Expression
843 /// @return A const pointer to the iteration Expression
844 const Expression* iteration() const { return mIteration.get(); }
845
846 private:
847 const tokens::LoopToken mLoopType;
848 Statement::UniquePtr mConditional;
849 Block::UniquePtr mBody;
850 Statement::UniquePtr mInitial;
851 Expression::UniquePtr mIteration;
852 };
853
854 /// @brief ConditionalStatements represents all combinations of 'if', 'else'
855 /// and 'else if' syntax and semantics. A single ConditionalStatement
856 /// only ever represents up to two branches; an 'if' (true) and an
857 /// optional 'else' (false). ConditionalStatements are nested within
858 /// the second 'else' branch to support 'else if' logic. As well as both
859 /// 'if' and 'else' branches, a ConditionalStatement also holds an
860 /// Expression related to its primary condition.
861 /// @note The first 'if' branch is referred to as the 'true' branch. The
862 /// second 'else' branch is referred to as the 'false' branch.
863 struct ConditionalStatement : public Statement
864 {
865 using UniquePtr = std::unique_ptr<ConditionalStatement>;
866
867 /// @brief Construct a new ConditionalStatement with an Expression
868 /// representing the primary condition, a Block representing the
869 /// 'true' branch and an optional Block representing the 'false'
870 /// branch. Ownership of all arguments is transferred to the
871 /// ConditionalStatement. All arguments have their parent data
872 /// updated.
873 /// @param conditional The Expression to construct the condition from
874 /// @param trueBlock The Block to construct the true branch from
875 /// @param falseBlock The (optional) Block to construct the false branch
876 /// from
877 349 ConditionalStatement(Expression* conditional,
878 Block* trueBlock,
879 Block* falseBlock = nullptr)
880 349 : mConditional(conditional)
881 , mTrueBranch(trueBlock)
882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
349 , mFalseBranch(falseBlock) {
883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
349 assert(mConditional);
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
349 assert(mTrueBranch);
885
1/2
✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
349 mConditional->setParent(this);
886
1/2
✓ Branch 1 taken 349 times.
✗ Branch 2 not taken.
349 mTrueBranch->setParent(this);
887
3/4
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 227 times.
✓ Branch 3 taken 122 times.
✗ Branch 4 not taken.
349 if (mFalseBranch) mFalseBranch->setParent(this);
888 349 }
889 /// @brief Deep copy constructor for an ConditionalStatement, performing a
890 /// deep copy on the condition and both held branches (Blocks),
891 /// ensuring parent information is updated.
892 /// @param other A const reference to another ConditionalStatement to deep
893 /// copy
894 90 ConditionalStatement(const ConditionalStatement& other)
895 90 : mConditional(other.mConditional->copy())
896 , mTrueBranch(other.mTrueBranch->copy())
897
4/6
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 60 times.
✓ Branch 7 taken 30 times.
✗ Branch 8 not taken.
90 , mFalseBranch(other.hasFalse() ? other.mFalseBranch->copy() : nullptr) {
898
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 mConditional->setParent(this);
899
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 mTrueBranch->setParent(this);
900
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 60 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
90 if (mFalseBranch) mFalseBranch->setParent(this);
901 90 }
902
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 287 times.
1756 ~ConditionalStatement() override = default;
903
904 /// @copybrief Node::copy()
905 90 ConditionalStatement* copy() const override final {
906
1/2
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
90 return new ConditionalStatement(*this);
907 }
908 /// @copybrief Node::nodetype()
909 6604 NodeType nodetype() const override { return Node::ConditionalStatementNode; }
910 /// @copybrief Node::nodename()
911 const char* nodename() const override { return "conditional statement"; }
912 /// @copybrief Node::subname()
913 const char* subname() const override { return "cond"; }
914 /// @copybrief Node::basetype()
915
1/4
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
96 const Statement* basetype() const override { return this; }
916
917 /// @copybrief Node::children()
918 4142 size_t children() const override final { return 3; }
919 /// @copybrief Node::child()
920 3137 const Statement* child(const size_t i) const override final {
921
18/24
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 318 times.
✓ Branch 4 taken 255 times.
✓ Branch 5 taken 510 times.
✓ Branch 6 taken 159 times.
✓ Branch 7 taken 318 times.
✓ Branch 8 taken 474 times.
✓ Branch 9 taken 944 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 270 times.
✓ Branch 13 taken 692 times.
✓ Branch 14 taken 9 times.
✓ Branch 15 taken 8 times.
✓ Branch 16 taken 2348 times.
✓ Branch 17 taken 4507 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1072 times.
✓ Branch 23 taken 2065 times.
14378 if (i == 0) return this->condition();
922
18/24
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 159 times.
✓ Branch 4 taken 255 times.
✓ Branch 5 taken 255 times.
✓ Branch 6 taken 159 times.
✓ Branch 7 taken 159 times.
✓ Branch 8 taken 474 times.
✓ Branch 9 taken 470 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 321 times.
✓ Branch 13 taken 371 times.
✓ Branch 14 taken 7 times.
✓ Branch 15 taken 1 times.
✓ Branch 16 taken 2278 times.
✓ Branch 17 taken 2229 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1033 times.
✓ Branch 23 taken 1032 times.
9542 if (i == 1) return this->trueBranch();
923
9/24
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 159 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 470 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 371 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2229 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1032 times.
✗ Branch 23 not taken.
4766 if (i == 2) return this->falseBranch();
924 return nullptr;
925 }
926 /// @copybrief Node::replacechild()
927 inline bool replacechild(const size_t i, Node* node) override final
928 {
929 if (i == 0) {
930 Expression* expr = dynamic_cast<Expression*>(node);
931 if (!expr) return false;
932 mConditional.reset(expr);
933 mConditional->setParent(this);
934 return true;
935 }
936 else if (i == 1 || i == 2) {
937 Block* blk = dynamic_cast<Block*>(node);
938 if (!blk) return false;
939 if (i == 1) {
940 mTrueBranch.reset(blk);
941 mTrueBranch->setParent(this);
942 }
943 else {
944 mFalseBranch.reset(blk);
945 mFalseBranch->setParent(this);
946 }
947 return true;
948 }
949 return false;
950 }
951
952 /// @brief Query if this ConditionalStatement has a valid 'false' branch
953 /// @return True if a valid 'false' branch exists, false otherwise
954 inline bool hasFalse() const {
955 return static_cast<bool>(this->falseBranch());
956 }
957 /// @brief Query the number of branches held by this ConditionalStatement.
958 /// This is only ever 1 or 2.
959 /// @return 2 if a valid 'true' and 'false' branch exist, 1 otherwise
960 size_t branchCount() const {
961 return this->hasFalse() ? 2 : 1;
962 }
963 /// @brief Access a const pointer to the ConditionalStatements condition
964 /// as an abstract expression.
965 /// @return A const pointer to the condition as an expression
966 const Expression* condition() const { return mConditional.get(); }
967 /// @brief Access a const pointer to the ConditionalStatements 'true'
968 /// branch as a Block
969 /// @return A const pointer to the 'true' branch
970 const Block* trueBranch() const { return mTrueBranch.get(); }
971 /// @brief Access a const pointer to the ConditionalStatements 'false'
972 /// branch as a Block
973 /// @return A const pointer to the 'false' branch
974 const Block* falseBranch() const { return mFalseBranch.get(); }
975 private:
976 Expression::UniquePtr mConditional;
977 Block::UniquePtr mTrueBranch;
978 Block::UniquePtr mFalseBranch;
979 };
980
981 /// @brief A BinaryOperator represents a single binary operation between a
982 /// left hand side (LHS) and right hand side (RHS) expression. The
983 /// operation type is stored as a tokens::OperatorToken enumerated type
984 /// on the node. AX grammar guarantees that this token will only ever
985 /// be a valid binary operator token type when initialized by the
986 /// parser.
987 struct BinaryOperator : public Expression
988 {
989 using UniquePtr = std::unique_ptr<BinaryOperator>;
990
991 /// @brief Construct a new BinaryOperator with a given
992 /// tokens::OperatorToken and a valid LHS and RHS expression,
993 /// transferring ownership of the expressions to the BinaryOperator
994 /// and updating parent data on the expressions.
995 /// @param left The left hand side of the binary expression
996 /// @param right The right hand side of the binary expression
997 /// @param op The binary token representing the operation to perform.
998 /// Should not be an assignment token.
999 2114 BinaryOperator(Expression* left,
1000 Expression* right,
1001 const tokens::OperatorToken op)
1002 2114 : mLeft(left)
1003 , mRight(right)
1004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2114 times.
2114 , mOperation(op) {
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2114 times.
2114 assert(mLeft);
1006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2114 times.
2114 assert(mRight);
1007
1/2
✓ Branch 1 taken 2114 times.
✗ Branch 2 not taken.
2114 mLeft->setParent(this);
1008
1/2
✓ Branch 1 taken 2114 times.
✗ Branch 2 not taken.
2114 mRight->setParent(this);
1009 2114 }
1010 /// @brief Construct a new BinaryOperator with a string, delegating
1011 /// construction to the above BinaryOperator constructor.
1012 /// @param left The left hand side of the binary expression
1013 /// @param right The right hand side of the binary expression
1014 /// @param op A string representing the binary operation to perform
1015 BinaryOperator(Expression* left,
1016 Expression* right,
1017 const std::string& op)
1018 : BinaryOperator(left, right, tokens::operatorTokenFromName(op)) {}
1019 /// @brief Deep copy constructor for a BinaryOperator, performing a
1020 /// deep copy on both held expressions, ensuring parent information
1021 /// is updated.
1022 /// @param other A const reference to another BinaryOperator to deep copy
1023 871 BinaryOperator(const BinaryOperator& other)
1024 871 : mLeft(other.mLeft->copy())
1025 871 , mRight(other.mRight->copy())
1026
2/4
✓ Branch 2 taken 871 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 871 times.
✗ Branch 6 not taken.
871 , mOperation(other.mOperation) {
1027
1/2
✓ Branch 1 taken 871 times.
✗ Branch 2 not taken.
871 mLeft->setParent(this);
1028
1/2
✓ Branch 1 taken 871 times.
✗ Branch 2 not taken.
871 mRight->setParent(this);
1029 871 }
1030
1/2
✓ Branch 0 taken 2985 times.
✗ Branch 1 not taken.
11940 ~BinaryOperator() override = default;
1031
1032 /// @copybrief Node::copy()
1033 871 BinaryOperator* copy() const override final {
1034
1/2
✓ Branch 2 taken 871 times.
✗ Branch 3 not taken.
871 return new BinaryOperator(*this);
1035 }
1036 /// @copybrief Node::nodetype()
1037 116779 NodeType nodetype() const override { return Node::BinaryOperatorNode; }
1038 /// @copybrief Node::nodename()
1039 const char* nodename() const override { return "binary"; }
1040 /// @copybrief Node::subname()
1041 const char* subname() const override { return "bin"; }
1042 /// @copybrief Node::basetype()
1043
1/6
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
144 const Expression* basetype() const override { return this; }
1044 /// @copybrief Node::children()
1045 17947 size_t children() const override final { return 2; }
1046 /// @copybrief Node::child()
1047 12017 const Expression* child(const size_t i) const override final {
1048
15/22
✓ Branch 0 taken 21727 times.
✓ Branch 1 taken 21654 times.
✓ Branch 2 taken 16533 times.
✓ Branch 3 taken 16533 times.
✓ Branch 4 taken 1866 times.
✓ Branch 5 taken 1866 times.
✓ Branch 6 taken 16533 times.
✓ Branch 7 taken 16533 times.
✓ Branch 8 taken 5956 times.
✓ Branch 9 taken 5956 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 15873 times.
✓ Branch 13 taken 15906 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 25376 times.
✓ Branch 17 taken 24126 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
206439 if (i == 0) return mLeft.get();
1049
7/22
✓ Branch 0 taken 21654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16533 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1866 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 16533 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5956 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 15906 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 24126 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
102574 if (i == 1) return mRight.get();
1050 return nullptr;
1051 }
1052 /// @copybrief Node::replacechild()
1053 inline bool replacechild(const size_t i, Node* node) override final {
1054 if (i > 1) return false;
1055 Expression* expr = dynamic_cast<Expression*>(node);
1056 if (!expr) return false;
1057 if (i == 0) {
1058 mLeft.reset(expr);
1059 mLeft->setParent(this);
1060 }
1061 else if (i == 1) {
1062 mRight.reset(expr);
1063 mRight->setParent(this);
1064 }
1065 return true;
1066 }
1067
1068 /// @brief Query the type of binary operation held on this node.
1069 /// @return The binary operation as a tokens::OperatorToken
1070
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 1729 times.
3673 inline tokens::OperatorToken operation() const { return mOperation; }
1071 /// @brief Access a const pointer to the BinaryOperator LHS as an abstract
1072 /// expression
1073 /// @return A const pointer to the LHS expression
1074 const Expression* lhs() const { return mLeft.get(); }
1075 /// @brief Access a const pointer to the BinaryOperator RHS as an abstract
1076 /// expression
1077 /// @return A const pointer to the RHS expression
1078 const Expression* rhs() const { return mRight.get(); }
1079 private:
1080 Expression::UniquePtr mLeft;
1081 Expression::UniquePtr mRight;
1082 const tokens::OperatorToken mOperation;
1083 };
1084
1085 /// @brief A TernaryOperator represents a ternary (conditional) expression
1086 /// 'a ? b : c' which evaluates to 'b' if 'a' is true and 'c' if 'a' is false.
1087 /// Requires 'b' and 'c' to be convertibly typed expressions, or both void.
1088 /// The 'true' expression ('b') is optional with the conditional expression 'a'
1089 /// returned if it evaluates to true, otherwise returning 'c'. Note that 'a'
1090 /// will only be evaluated once in this case.
1091 struct TernaryOperator : public Expression
1092 {
1093 using UniquePtr = std::unique_ptr<TernaryOperator>;
1094
1095 /// @brief Construct a new TernaryOperator with a conditional expression
1096 /// and true (optional) and false expressions, transferring
1097 /// ownership of the expressions to the TernaryOperator
1098 /// and updating parent data on the expressions.
1099 /// @param conditional The conditional expression determining the expression
1100 /// selection
1101 /// @param trueExpression The (optional) expression evaluated if the condition
1102 /// is true
1103 /// @param falseExpression The expression evaluated if the condition is false
1104 266 TernaryOperator(Expression* conditional,
1105 Expression* trueExpression,
1106 Expression* falseExpression)
1107 266 : mConditional(conditional)
1108 , mTrueBranch(trueExpression)
1109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
266 , mFalseBranch(falseExpression) {
1110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
266 assert(mConditional);
1111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
266 assert(mFalseBranch);
1112
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 mConditional->setParent(this);
1113
3/4
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 27 times.
✓ Branch 3 taken 239 times.
✗ Branch 4 not taken.
266 if (mTrueBranch) mTrueBranch->setParent(this);
1114
1/2
✓ Branch 1 taken 266 times.
✗ Branch 2 not taken.
266 mFalseBranch->setParent(this);
1115 266 }
1116 /// @brief Deep copy constructor for a TernaryOperator, performing a
1117 /// deep copy on held expressions, ensuring parent information
1118 /// is updated.
1119 /// @param other A const reference to another TernaryOperator to deep copy
1120 80 TernaryOperator(const TernaryOperator& other)
1121 80 : mConditional(other.mConditional->copy())
1122
1/2
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
72 , mTrueBranch(other.hasTrue() ? other.mTrueBranch->copy() : nullptr)
1123
3/4
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 80 times.
✗ Branch 5 not taken.
152 , mFalseBranch(other.mFalseBranch->copy()) {
1124
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 mConditional->setParent(this);
1125
3/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 72 times.
✗ Branch 4 not taken.
80 if (mTrueBranch) mTrueBranch->setParent(this);
1126
1/2
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
80 mFalseBranch->setParent(this);
1127 80 }
1128
1/2
✓ Branch 0 taken 346 times.
✗ Branch 1 not taken.
1384 ~TernaryOperator() override = default;
1129
1130 /// @copybrief Node::copy()
1131 80 TernaryOperator* copy() const override final {
1132
1/2
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
80 return new TernaryOperator(*this);
1133 }
1134 /// @copybrief Node::nodetype()
1135 8612 NodeType nodetype() const override { return Node::TernaryOperatorNode; }
1136 /// @copybrief Node::nodename()
1137 const char* nodename() const override { return "ternary"; }
1138 /// @copybrief Node::subname()
1139 const char* subname() const override { return "tern"; }
1140 /// @copybrief Node::basetype()
1141
1/6
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
42 const Expression* basetype() const override { return this; }
1142 /// @copybrief Node::children()
1143 4045 size_t children() const override final { return 3; }
1144 /// @copybrief Node::child()
1145 3088 const Expression* child(const size_t i) const override final {
1146
16/22
✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 2486 times.
✓ Branch 2 taken 302 times.
✓ Branch 3 taken 604 times.
✓ Branch 4 taken 196 times.
✓ Branch 5 taken 392 times.
✓ Branch 6 taken 302 times.
✓ Branch 7 taken 604 times.
✓ Branch 8 taken 520 times.
✓ Branch 9 taken 1040 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2314 times.
✓ Branch 13 taken 4643 times.
✓ Branch 14 taken 6 times.
✓ Branch 15 taken 8 times.
✓ Branch 16 taken 3872 times.
✓ Branch 17 taken 7665 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
26240 if (i == 0) return mConditional.get();
1147
16/22
✓ Branch 0 taken 1251 times.
✓ Branch 1 taken 1235 times.
✓ Branch 2 taken 302 times.
✓ Branch 3 taken 302 times.
✓ Branch 4 taken 196 times.
✓ Branch 5 taken 196 times.
✓ Branch 6 taken 302 times.
✓ Branch 7 taken 302 times.
✓ Branch 8 taken 520 times.
✓ Branch 9 taken 520 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2318 times.
✓ Branch 13 taken 2325 times.
✓ Branch 14 taken 5 times.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 3844 times.
✓ Branch 17 taken 3821 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
17442 if (i == 1) return mTrueBranch.get();
1148
8/22
✓ Branch 0 taken 1235 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 302 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 196 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 302 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 520 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2325 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3821 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
8704 if (i == 2) return mFalseBranch.get();
1149 return nullptr;
1150 }
1151 /// @copybrief Node::replacechild()
1152 inline bool replacechild(const size_t i, Node* node) override final {
1153 if (i > 2) return false;
1154 Expression* expr = dynamic_cast<Expression*>(node);
1155 if (!expr) return false;
1156 if (i == 0) {
1157 mConditional.reset(expr);
1158 mConditional->setParent(this);
1159 }
1160 else if (i == 1) {
1161 mTrueBranch.reset(expr);
1162 mTrueBranch->setParent(this);
1163 }
1164 else if (i == 2) {
1165 mFalseBranch.reset(expr);
1166 mFalseBranch->setParent(this);
1167 }
1168 return true;
1169 }
1170
1171 /// @brief Query whether or not this has an optional if-true branch.
1172 bool hasTrue() const { return static_cast<bool>(this->trueBranch()); }
1173 /// @brief Access a const pointer to the TernaryOperator conditional as
1174 /// an abstract expression
1175 /// @return A const pointer to the conditional expression
1176 const Expression* condition() const { return mConditional.get(); }
1177 /// @brief Access a const pointer to the TernaryOperator true expression as
1178 /// an abstract expression
1179 /// @return A const pointer to the true expression
1180 const Expression* trueBranch() const { return mTrueBranch.get(); }
1181 /// @brief Access a const pointer to the TernaryOperator false expression as
1182 /// an abstract expression
1183 /// @return A const pointer to the false expression
1184 const Expression* falseBranch() const { return mFalseBranch.get(); }
1185 private:
1186 Expression::UniquePtr mConditional;
1187 Expression::UniquePtr mTrueBranch;
1188 Expression::UniquePtr mFalseBranch;
1189 };
1190
1191 /// @brief AssignExpressions represents a similar object construction to a
1192 /// BinaryOperator. AssignExpressions can be chained together and are
1193 /// thus derived as Expressions rather than Statements.
1194 /// @note AssignExpressions can either be direct or compound assignments. The
1195 /// latter is represented by the last argument in the primary
1196 /// constructor which is expected to be a valid binary token.
1197 struct AssignExpression : public Expression
1198 {
1199 using UniquePtr = std::unique_ptr<AssignExpression>;
1200
1201 /// @brief Construct a new AssignExpression with valid LHS and RHS
1202 /// expressions, transferring ownership of the expressions to the
1203 /// AssignExpression and updating parent data on the expressions.
1204 /// @param lhs The left hand side of the assign expression
1205 /// @param rhs The right hand side of the assign expression
1206 /// @param op The compound assignment token, if any
1207 11791 AssignExpression(Expression* lhs, Expression* rhs,
1208 const tokens::OperatorToken op = tokens::EQUALS)
1209 11791 : mLHS(lhs)
1210 , mRHS(rhs)
1211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11791 times.
11791 , mOperation(op) {
1212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11791 times.
11791 assert(mLHS);
1213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11791 times.
11791 assert(mRHS);
1214
1/2
✓ Branch 1 taken 11791 times.
✗ Branch 2 not taken.
11791 mLHS->setParent(this);
1215
1/2
✓ Branch 1 taken 11791 times.
✗ Branch 2 not taken.
11791 mRHS->setParent(this);
1216 11791 }
1217 /// @brief Deep copy constructor for an AssignExpression, performing a
1218 /// deep copy on both held expressions, ensuring parent information
1219 /// is updated.
1220 /// @param other A const reference to another AssignExpression to deep
1221 /// copy
1222 5737 AssignExpression(const AssignExpression& other)
1223 5737 : mLHS(other.mLHS->copy())
1224 5737 , mRHS(other.mRHS->copy())
1225
2/4
✓ Branch 2 taken 5737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5737 times.
✗ Branch 6 not taken.
5737 , mOperation(other.mOperation) {
1226
1/2
✓ Branch 1 taken 5737 times.
✗ Branch 2 not taken.
5737 mLHS->setParent(this);
1227
1/2
✓ Branch 1 taken 5737 times.
✗ Branch 2 not taken.
5737 mRHS->setParent(this);
1228 5737 }
1229
1/2
✓ Branch 0 taken 17528 times.
✗ Branch 1 not taken.
70112 ~AssignExpression() override = default;
1230
1231 /// @copybrief Node::copy()
1232 5737 AssignExpression* copy() const override final {
1233
1/2
✓ Branch 2 taken 5737 times.
✗ Branch 3 not taken.
5737 return new AssignExpression(*this);
1234 }
1235 /// @copybrief Node::nodetype()
1236 366939 NodeType nodetype() const override { return Node::AssignExpressionNode; }
1237 /// @copybrief Node::nodename()
1238 const char* nodename() const override { return "assignment expression"; }
1239 /// @copybrief Node::subname()
1240 const char* subname() const override { return "asgn"; }
1241 /// @copybrief Node::basetype()
1242
3/6
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
144 const Expression* basetype() const override { return this; }
1243 /// @copybrief Node::children()
1244 105792 size_t children() const override final { return 2; }
1245 /// @copybrief Node::child()
1246 71950 const Expression* child(const size_t i) const override final {
1247
22/24
✓ Branch 0 taken 17352 times.
✓ Branch 1 taken 17352 times.
✓ Branch 2 taken 11586 times.
✓ Branch 3 taken 11586 times.
✓ Branch 4 taken 11560 times.
✓ Branch 5 taken 11560 times.
✓ Branch 6 taken 11583 times.
✓ Branch 7 taken 11583 times.
✓ Branch 8 taken 39765 times.
✓ Branch 9 taken 39765 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 74513 times.
✓ Branch 13 taken 75445 times.
✓ Branch 14 taken 47 times.
✓ Branch 15 taken 14 times.
✓ Branch 16 taken 152290 times.
✓ Branch 17 taken 142805 times.
✓ Branch 18 taken 3 times.
✓ Branch 19 taken 3 times.
✓ Branch 20 taken 3 times.
✓ Branch 21 taken 3 times.
✓ Branch 22 taken 35672 times.
✓ Branch 23 taken 36278 times.
700768 if (i == 0) return this->lhs();
1248
11/24
✓ Branch 0 taken 17352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11586 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11560 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11583 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 39765 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 75445 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 14 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 142805 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 36278 times.
✗ Branch 23 not taken.
346394 if (i == 1) return this->rhs();
1249 return nullptr;
1250 }
1251 /// @copybrief Node::replacechild()
1252 4 inline bool replacechild(const size_t i, Node* node) override final {
1253
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (i > 1) return false;
1254
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 Expression* expr = dynamic_cast<Expression*>(node);
1255
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!expr) return false;
1256
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (i == 0) {
1257 mLHS.reset(expr);
1258 2 mLHS->setParent(this);
1259 }
1260
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (i == 1) {
1261 mRHS.reset(expr);
1262 2 mRHS->setParent(this);
1263 }
1264 return true;
1265 }
1266
1267 /// @brief Query whether or not this is a compound AssignExpression.
1268 /// Compound AssignExpressions are assignments which read and write
1269 /// to the LHS value. i.e. +=, -=, *= etc
1270 /// @return The binary operation as a tokens::OperatorToken
1271
4/4
✓ Branch 0 taken 10781 times.
✓ Branch 1 taken 10974 times.
✓ Branch 2 taken 1616 times.
✓ Branch 3 taken 15728 times.
39099 inline bool isCompound() const { return mOperation != tokens::EQUALS; }
1272 /// @brief Query the actual operational type of this AssignExpression. For
1273 /// simple (non-compound) AssignExpressions, tokens::EQUALS is
1274 /// returned.
1275
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
85 inline tokens::OperatorToken operation() const { return mOperation; }
1276 /// @brief Access a const pointer to the AssignExpression LHS as an
1277 /// abstract expression
1278 /// @return A const pointer to the LHS expression
1279 const Expression* lhs() const { return mLHS.get(); }
1280 /// @brief Access a const pointer to the AssignExpression RHS as an
1281 //// abstract expression
1282 /// @return A const pointer to the RHS expression
1283 const Expression* rhs() const { return mRHS.get(); }
1284 private:
1285 Expression::UniquePtr mLHS;
1286 Expression::UniquePtr mRHS;
1287 const tokens::OperatorToken mOperation;
1288 };
1289
1290 /// @brief A Crement node represents a single increment '++' and decrement '--'
1291 /// operation. As well as it's crement type, it also stores whether
1292 /// the semantics constructed a post or pre-crement i.e. ++a or a++.
1293 struct Crement : public Expression
1294 {
1295 using UniquePtr = std::unique_ptr<Crement>;
1296
1297 /// @brief A simple enum representing the crement type.
1298 enum Operation {
1299 Increment,
1300 Decrement
1301 };
1302
1303 /// @brief Construct a new Crement with a valid expression, transferring
1304 /// ownership of the expression to the Crement node and updating
1305 /// parent data on the expression.
1306 /// @param expr The expression to crement
1307 /// @param op The type of crement operation; Increment or Decrement
1308 /// @param post True if the crement operation is a post crement i.e. a++,
1309 /// false if the operation is a pre crement i.e. ++a
1310 961 Crement(Expression* expr, const Operation op, bool post)
1311 961 : mExpression(expr)
1312 , mOperation(op)
1313
1/2
✓ Branch 1 taken 961 times.
✗ Branch 2 not taken.
961 , mPost(post) {
1314
1/2
✓ Branch 1 taken 961 times.
✗ Branch 2 not taken.
961 mExpression->setParent(this);
1315 961 }
1316 /// @brief Deep copy constructor for a Crement, performing a deep copy on
1317 /// the underlying expressions, ensuring parent information is
1318 /// updated.
1319 /// @param other A const reference to another Crement to deep copy
1320 384 Crement(const Crement& other)
1321 384 : mExpression(other.mExpression->copy())
1322 384 , mOperation(other.mOperation)
1323 384 , mPost(other.mPost) {
1324
1/2
✓ Branch 1 taken 384 times.
✗ Branch 2 not taken.
384 mExpression->setParent(this);
1325 384 }
1326
1/2
✓ Branch 0 taken 1345 times.
✗ Branch 1 not taken.
5380 ~Crement() override = default;
1327
1328 /// @copybrief Node::copy()
1329
1/2
✓ Branch 2 taken 384 times.
✗ Branch 3 not taken.
384 Crement* copy() const override final { return new Crement(*this); }
1330 /// @copybrief Node::nodetype()
1331 31904 NodeType nodetype() const override { return Node::CrementNode; }
1332 /// @copybrief Node::nodename()
1333 const char* nodename() const override { return "crement"; }
1334 /// @copybrief Node::subname()
1335 const char* subname() const override { return "crmt"; }
1336 /// @copybrief Node::basetype()
1337
1/6
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
114 const Expression* basetype() const override { return this; }
1338 //
1339 /// @copybrief Node::children()
1340 2690 size_t children() const override final { return 1; }
1341 /// @copybrief Node::child()
1342 1345 const Expression* child(const size_t i) const override final {
1343
1/2
✓ Branch 0 taken 6668 times.
✗ Branch 1 not taken.
6668 if (i == 0) return this->expression();
1344 return nullptr;
1345 }
1346 /// @copybrief Node::replacechild()
1347 inline bool replacechild(const size_t i, Node* node) override final {
1348 if (i != 0) return false;
1349 Expression* expr = dynamic_cast<Expression*>(node);
1350 if (!expr) return false;
1351 mExpression.reset(expr);
1352 mExpression->setParent(this);
1353 return true;
1354 }
1355
1356 /// @brief Query the type of the Crement operation. This does not hold
1357 /// post or pre-crement information.
1358 /// @return The Crement operation being performed. This is either an
1359 /// Crement::Increment or Crement::Decrement.
1360
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 inline Operation operation() const { return mOperation; }
1361 /// @brief Query if this Crement node represents an incrementation ++
1362 /// @return True if this node is performing an increment
1363
2/4
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 465 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
772 inline bool increment() const { return mOperation == Increment; }
1364 /// @brief Query if this Crement node represents an decrement --
1365 /// @return True if this node is performing an decrement
1366
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 inline bool decrement() const { return mOperation == Decrement; }
1367 /// @brief Query if this Crement node represents a pre crement ++a
1368 /// @return True if this node is performing a pre crement
1369
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 inline bool pre() const { return !mPost; }
1370 /// @brief Query if this Crement node represents a post crement a++
1371 /// @return True if this node is performing a post crement
1372
2/4
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 430 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
829 inline bool post() const { return mPost; }
1373 /// @brief Access a const pointer to the expression being crements as an
1374 /// abstract Expression
1375 /// @return A const pointer to the expression
1376 const Expression* expression() const { return mExpression.get(); }
1377 private:
1378 Expression::UniquePtr mExpression;
1379 const Operation mOperation;
1380 const bool mPost;
1381 };
1382
1383 /// @brief A UnaryOperator represents a single unary operation on an
1384 /// expression. The operation type is stored as a tokens::OperatorToken
1385 /// enumerated type on the node. AX grammar guarantees that this token
1386 /// will only every be a valid unary operator token type when
1387 /// initialized by the parser.
1388 struct UnaryOperator : public Expression
1389 {
1390 using UniquePtr = std::unique_ptr<UnaryOperator>;
1391
1392 /// @brief Construct a new UnaryOperator with a given tokens::OperatorToken
1393 /// and a valid expression, transferring ownership of the expression
1394 /// to the UnaryOperator and updating parent data on the expression.
1395 /// @param expr The expression to perform the unary operator on
1396 /// @param op The unary token representing the operation to perform.
1397 3814 UnaryOperator(Expression* expr, const tokens::OperatorToken op)
1398 3814 : mExpression(expr)
1399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3814 times.
3814 , mOperation(op) {
1400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3814 times.
3814 assert(mExpression);
1401
1/2
✓ Branch 1 taken 3814 times.
✗ Branch 2 not taken.
3814 mExpression->setParent(this);
1402 3814 }
1403 /// @brief Construct a new UnaryOperator with a string, delegating
1404 /// construction to the above UnaryOperator constructor.
1405 /// @param op A string representing the unary operation to perform
1406 /// @param expr The expression to perform the unary operator on
1407 UnaryOperator(Expression* expr, const std::string& op)
1408 : UnaryOperator(expr, tokens::operatorTokenFromName(op)) {}
1409 /// @brief Deep copy constructor for a UnaryOperator, performing a deep
1410 /// copy on the underlying expressions, ensuring parent information
1411 /// is updated.
1412 /// @param other A const reference to another UnaryOperator to deep copy
1413 1837 UnaryOperator(const UnaryOperator& other)
1414 1837 : mExpression(other.mExpression->copy())
1415 1837 , mOperation(other.mOperation) {
1416
1/2
✓ Branch 1 taken 1837 times.
✗ Branch 2 not taken.
1837 mExpression->setParent(this);
1417 1837 }
1418
1/2
✓ Branch 0 taken 5651 times.
✗ Branch 1 not taken.
22604 ~UnaryOperator() override = default;
1419
1420 /// @copybrief Node::copy()
1421
1/2
✓ Branch 2 taken 1837 times.
✗ Branch 3 not taken.
1837 UnaryOperator* copy() const override final { return new UnaryOperator(*this); }
1422 /// @copybrief Node::nodetype()
1423 110525 NodeType nodetype() const override { return Node::UnaryOperatorNode; }
1424 /// @copybrief Node::nodename()
1425 const char* nodename() const override { return "unary"; }
1426 /// @copybrief Node::subname()
1427 const char* subname() const override { return "unry"; }
1428 /// @copybrief Node::basetype()
1429
1/6
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
84 const Expression* basetype() const override { return this; }
1430 /// @copybrief Node::children()
1431 11302 size_t children() const override final { return 1; }
1432 /// @copybrief Node::child()
1433 5651 const Expression* child(const size_t i) const override final {
1434
1/2
✓ Branch 0 taken 36398 times.
✗ Branch 1 not taken.
36398 if (i == 0) return this->expression();
1435 return nullptr;
1436 }
1437 /// @copybrief Node::replacechild()
1438 inline bool replacechild(const size_t i, Node* node) override final {
1439 if (i != 0) return false;
1440 Expression* expr = dynamic_cast<Expression*>(node);
1441 if (!expr) return false;
1442 mExpression.reset(expr);
1443 mExpression->setParent(this);
1444 return true;
1445 }
1446
1447 /// @brief Query the type of unary operation held on this node.
1448 /// @return The unary operation as a tokens::OperatorToken
1449
2/2
✓ Branch 0 taken 3602 times.
✓ Branch 1 taken 80 times.
3682 inline tokens::OperatorToken operation() const { return mOperation; }
1450 /// @brief Access a const pointer to the UnaryOperator expression as an
1451 /// abstract expression
1452 /// @return A const pointer to the expression
1453 const Expression* expression() const { return mExpression.get(); }
1454 private:
1455 Expression::UniquePtr mExpression;
1456 const tokens::OperatorToken mOperation;
1457 };
1458
1459 /// @brief Cast nodes represent the conversion of an underlying expression to
1460 /// a target type. Cast nodes are typically constructed from functional
1461 /// notation and do not represent construction of the target type,
1462 /// rather a type-casted conversion.
1463 struct Cast : public Expression
1464 {
1465 using UniquePtr = std::unique_ptr<Cast>;
1466
1467 /// @brief Construct a new Cast with a valid expression and a target
1468 /// tokens::CoreType, transferring ownership of the expression to
1469 /// the Cast and updating parent data on the expression.
1470 /// @param expr The expression to perform the cast operator on
1471 /// @param type The target cast type
1472 191 Cast(Expression* expr, const tokens::CoreType type)
1473 191 : Expression()
1474 , mType(type)
1475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 191 times.
191 , mExpression(expr) {
1476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 191 times.
191 assert(mExpression);
1477
1/2
✓ Branch 1 taken 191 times.
✗ Branch 2 not taken.
191 mExpression->setParent(this);
1478 191 }
1479 /// @brief Deep copy constructor for a Cast node, performing a deep copy on
1480 /// the underlying expressions, ensuring parent information is
1481 /// updated.
1482 /// @param other A const reference to another Cast node to deep copy
1483 40 Cast(const Cast& other)
1484 40 : Expression()
1485 40 , mType(other.mType)
1486 40 , mExpression(other.mExpression->copy()) {
1487
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 mExpression->setParent(this);
1488 40 }
1489
1/2
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
924 ~Cast() override = default;
1490
1491 /// @copybrief Node::copy()
1492
1/2
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
40 Cast* copy() const override final { return new Cast(*this); }
1493 /// @copybrief Node::nodetype()
1494 2377 NodeType nodetype() const override { return Node::CastNode; }
1495 /// @copybrief Node::nodename()
1496 const char* nodename() const override { return "cast"; }
1497 /// @copybrief Node::subname()
1498 const char* subname() const override { return "cast"; }
1499 /// @copybrief Node::basetype()
1500
1/6
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
72 const Expression* basetype() const override { return this; }
1501 /// @copybrief Node::children()
1502 462 size_t children() const override final { return 1; }
1503 /// @copybrief Node::child()
1504 231 const Expression* child(const size_t i) const override final {
1505
1/2
✓ Branch 0 taken 633 times.
✗ Branch 1 not taken.
633 if (i == 0) return this->expression();
1506 return nullptr;
1507 }
1508 /// @copybrief Node::replacechild()
1509 inline bool replacechild(const size_t i, Node* node) override final {
1510 if (i != 0) return false;
1511 Expression* expr = dynamic_cast<Expression*>(node);
1512 if (!expr) return false;
1513 mExpression.reset(expr);
1514 mExpression->setParent(this);
1515 return true;
1516 }
1517
1518 /// @brief Access to the target type
1519 /// @return a tokens::CoreType enumerable type therepresenting the target type
1520
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
118 inline tokens::CoreType type() const { return mType; }
1521 /// @brief Get the target type as a front end AX type/token string
1522 /// @note This returns the associated token to the type, not necessarily
1523 /// equal to the OpenVDB type string
1524 /// @return A string representing the type/token
1525 inline std::string typestr() const {
1526 return ast::tokens::typeStringFromToken(mType);
1527 }
1528 /// @brief Access a const pointer to the Cast node's expression as an
1529 /// abstract expression
1530 /// @return A const pointer to the expression
1531 const Expression* expression() const { return mExpression.get(); }
1532 private:
1533 const tokens::CoreType mType;
1534 Expression::UniquePtr mExpression;
1535 };
1536
1537 /// @brief FunctionCalls represent a single call to a function and any provided
1538 /// arguments. The argument list can be empty. The function name is
1539 /// expected to exist in the AX function registry.
1540 struct FunctionCall : public Expression
1541 {
1542 using UniquePtr = std::unique_ptr<FunctionCall>;
1543
1544 /// @brief Construct a new FunctionCall with a given function identifier
1545 /// and an optional argument, transferring ownership of any
1546 /// provided argument to the FunctionCall and updating parent data
1547 /// on the arguments.
1548 /// @param function The name/identifier of the function
1549 /// @param argument Function argument
1550 5075 FunctionCall(const std::string& function,
1551 Expression* argument = nullptr)
1552 5075 : mFunctionName(function)
1553
1/2
✓ Branch 2 taken 5075 times.
✗ Branch 3 not taken.
5075 , mArguments() {
1554
1/2
✓ Branch 1 taken 5075 times.
✗ Branch 2 not taken.
5075 this->append(argument);
1555 5075 }
1556 /// @brief Construct a new FunctionCall with a given function identifier
1557 /// and optional argument list, transferring ownership of any
1558 /// provided arguments to the FunctionCall and updating parent data
1559 /// on the arguments.
1560 /// @param function The name/identifier of the function
1561 /// @param arguments Function arguments
1562 3 FunctionCall(const std::string& function,
1563 const std::vector<Expression*>& arguments)
1564 3 : mFunctionName(function)
1565
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 , mArguments() {
1566
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 mArguments.reserve(arguments.size());
1567
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3 times.
13 for (Expression* arg : arguments) {
1568
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 this->append(arg);
1569 }
1570 3 }
1571 /// @brief Deep copy constructor for a FunctionCall, performing a deep copy
1572 /// on all held function arguments, ensuring parent information is
1573 /// updated.
1574 /// @param other A const reference to another FunctionCall to deep copy
1575 2484 FunctionCall(const FunctionCall& other)
1576 2484 : mFunctionName(other.mFunctionName)
1577
1/2
✓ Branch 2 taken 2484 times.
✗ Branch 3 not taken.
2484 , mArguments() {
1578
1/2
✓ Branch 1 taken 2484 times.
✗ Branch 2 not taken.
2484 mArguments.reserve(other.mArguments.size());
1579
2/2
✓ Branch 0 taken 3488 times.
✓ Branch 1 taken 2484 times.
5972 for (const Expression::UniquePtr& expr : other.mArguments) {
1580
2/4
✓ Branch 1 taken 3488 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3488 times.
✗ Branch 5 not taken.
3488 this->append(expr->copy());
1581 }
1582 2484 }
1583 30248 ~FunctionCall() override = default;
1584
1585 /// @copybrief Node::copy()
1586
1/2
✓ Branch 2 taken 2484 times.
✗ Branch 3 not taken.
2484 FunctionCall* copy() const override final { return new FunctionCall(*this); }
1587 /// @copybrief Node::nodetype()
1588 158152 NodeType nodetype() const override { return Node::FunctionCallNode; }
1589 /// @copybrief Node::nodename()
1590 const char* nodename() const override { return "function call"; }
1591 /// @copybrief Node::subname()
1592 const char* subname() const override { return "call"; }
1593 /// @copybrief Node::basetype()
1594
1/6
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
82 const Expression* basetype() const override { return this; }
1595 /// @copybrief Node::children()
1596 26566 size_t children() const override final { return this->size(); }
1597 /// @copybrief Node::child()
1598
1/2
✓ Branch 0 taken 16037 times.
✗ Branch 1 not taken.
16037 const Expression* child(const size_t i) const override final {
1599
7/22
✓ Branch 0 taken 33311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13783 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6997 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13783 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24176 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 46344 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 73179 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
211573 if (i >= mArguments.size()) return nullptr;
1600 211573 return mArguments[i].get();
1601 }
1602 /// @copybrief Node::replacechild()
1603 inline bool replacechild(const size_t i, Node* node) override final {
1604 if (mArguments.size() <= i) return false;
1605 Expression* expr = dynamic_cast<Expression*>(node);
1606 mArguments[i].reset(expr);
1607 mArguments[i]->setParent(this);
1608 return true;
1609 }
1610
1611 /// @brief Access the function name/identifier
1612 /// @return A const reference to the function name
1613
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 17098 times.
22105 inline const std::string& name() const { return mFunctionName; }
1614 /// @brief Query the total number of arguments stored on this function
1615 /// @return The number of arguments. Can be 0
1616 inline size_t numArgs() const { return mArguments.size(); }
1617
1618 /// @brief Alias for FunctionCall::children
1619 inline size_t size() const { return mArguments.size(); }
1620 /// @brief Query whether this Expression list holds any valid expressions
1621 /// @return True if this node if empty, false otherwise
1622 inline bool empty() const { return mArguments.empty(); }
1623 /// @brief Appends an argument to this function call, transferring
1624 /// ownership to the FunctionCall and updating parent data on the
1625 /// expression. If the expression is a nullptr, it is ignored.
1626 15586 inline void append(Expression* expr) {
1627
2/2
✓ Branch 0 taken 10529 times.
✓ Branch 1 taken 5057 times.
15586 if (expr) {
1628 10529 mArguments.emplace_back(expr);
1629 10529 expr->setParent(this);
1630 }
1631 15586 }
1632 private:
1633 const std::string mFunctionName;
1634 std::vector<Expression::UniquePtr> mArguments;
1635 };
1636
1637 /// @brief Keywords represent keyword statements defining changes in execution.
1638 /// These include those that define changes in loop execution such as
1639 /// break and continue, as well as return statements.
1640 struct Keyword : public Statement
1641 {
1642 using UniquePtr = std::unique_ptr<Keyword>;
1643
1644 /// @brief Construct a new Keyword with a given tokens::KeywordToken.
1645 /// @param keyw The keyword token.
1646 Keyword(const tokens::KeywordToken keyw)
1647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 : mKeyword(keyw) {}
1648 /// @brief Deep copy constructor for a Keyword.
1649 /// @param other A const reference to another Keyword to deep copy
1650 Keyword(const Keyword& other)
1651 44 : mKeyword(other.mKeyword) {}
1652 292 ~Keyword() override = default;
1653
1654 /// @copybrief Node::copy()
1655 44 Keyword* copy() const override final { return new Keyword(*this); }
1656 /// @copybrief Node::nodetype()
1657 3075 NodeType nodetype() const override { return Node::KeywordNode; }
1658 /// @copybrief Node::nodename()
1659 const char* nodename() const override { return "keyword"; }
1660 /// @copybrief Node::subname()
1661 const char* subname() const override { return "keyw"; }
1662 /// @copybrief Node::basetype()
1663
1/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 const Statement* basetype() const override { return this; }
1664 /// @copybrief Node::children()
1665 size_t children() const override final { return 0; }
1666 /// @copybrief Node::child()
1667 const Node* child(const size_t) const override final {
1668 return nullptr;
1669 }
1670 /// @brief Query the keyword held on this node.
1671 /// @return The keyword as a tokens::KeywordToken
1672
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 89 times.
95 inline tokens::KeywordToken keyword() const { return mKeyword; }
1673
1674 private:
1675 const tokens::KeywordToken mKeyword;
1676 };
1677
1678 /// @brief ArrayUnpack represent indexing operations into AX container types,
1679 /// primarily vectors and matrices indexed by the square brackets []
1680 /// syntax. Multiple levels of indirection (multiple components) can
1681 /// be specified but current construction is limited to either a single
1682 /// or double component lookup. Providing two components infers a matrix
1683 /// indexing operation.
1684 /// @note Single indexing operations are still valid for matrix indexing
1685 struct ArrayUnpack : public Expression
1686 {
1687 using UniquePtr = std::unique_ptr<ArrayUnpack>;
1688
1689 /// @brief Construct a new ArrayUnpack with a valid expression, an initial
1690 /// component (as an expression) to the first access and an optional
1691 /// second component (as an expression) to a second access.
1692 /// @note Providing a second component automatically infers this
1693 /// ArrayUnpack as a matrix indexing operation. Ownership is
1694 /// transferred and parent data is updated for all arguments.
1695 /// @param expr The expression to perform the unpacking operation on
1696 /// @param component0 The first component access
1697 /// @param component1 The second component access
1698 4021 ArrayUnpack(Expression* expr,
1699 Expression* component0,
1700 Expression* component1 = nullptr)
1701 4021 : mIdx0(component0)
1702 , mIdx1(component1)
1703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4021 times.
4021 , mExpression(expr) {
1704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4021 times.
4021 assert(mIdx0);
1705
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4021 times.
4021 assert(mExpression);
1706
1/2
✓ Branch 1 taken 4021 times.
✗ Branch 2 not taken.
4021 mIdx0->setParent(this);
1707
3/4
✓ Branch 0 taken 698 times.
✓ Branch 1 taken 3323 times.
✓ Branch 3 taken 698 times.
✗ Branch 4 not taken.
4021 if(mIdx1) mIdx1->setParent(this);
1708
1/2
✓ Branch 1 taken 4021 times.
✗ Branch 2 not taken.
4021 mExpression->setParent(this);
1709 4021 }
1710 /// @brief Deep copy constructor for a ArrayUnpack, performing a deep
1711 /// copy on the expression being indexed and all held components,
1712 /// ensuring parent information is updated.
1713 /// @param other A const reference to another ArrayUnpack to deep copy
1714 1277 ArrayUnpack(const ArrayUnpack& other)
1715
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1069 times.
1277 : ArrayUnpack(other.mExpression->copy(),
1716 1277 other.mIdx0->copy(),
1717
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1069 times.
1277 other.mIdx1 ? other.mIdx1->copy() : nullptr) {}
1718
1719
1/2
✓ Branch 0 taken 4021 times.
✗ Branch 1 not taken.
16084 ~ArrayUnpack() override = default;
1720
1721 /// @copybrief Node::copy()
1722
1/2
✓ Branch 2 taken 1277 times.
✗ Branch 3 not taken.
1277 ArrayUnpack* copy() const override final { return new ArrayUnpack(*this); }
1723 /// @copybrief Node::nodetype()
1724 141073 NodeType nodetype() const override { return Node::ArrayUnpackNode; }
1725 /// @copybrief Node::nodename()
1726 const char* nodename() const override { return "array unpack"; }
1727 /// @copybrief Node::subname()
1728 const char* subname() const override { return "unpk"; }
1729 /// @copybrief Node::basetype()
1730
3/6
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
142 const Expression* basetype() const override { return this; }
1731 /// @copybrief Node::children()
1732 34975 size_t children() const override final { return 3; }
1733 /// @copybrief Node::child()
1734 26238 const Statement* child(const size_t i) const override final {
1735
22/24
✓ Branch 0 taken 8038 times.
✓ Branch 1 taken 16076 times.
✓ Branch 2 taken 6754 times.
✓ Branch 3 taken 13508 times.
✓ Branch 4 taken 2644 times.
✓ Branch 5 taken 5288 times.
✓ Branch 6 taken 6753 times.
✓ Branch 7 taken 13506 times.
✓ Branch 8 taken 8628 times.
✓ Branch 9 taken 17256 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 15884 times.
✓ Branch 13 taken 32271 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 4 times.
✓ Branch 16 taken 76685 times.
✓ Branch 17 taken 153370 times.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 2 times.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 2 times.
✓ Branch 22 taken 8746 times.
✓ Branch 23 taken 17492 times.
402911 if (i == 0) return this->component0();
1736
22/24
✓ Branch 0 taken 8038 times.
✓ Branch 1 taken 8038 times.
✓ Branch 2 taken 6754 times.
✓ Branch 3 taken 6754 times.
✓ Branch 4 taken 2644 times.
✓ Branch 5 taken 2644 times.
✓ Branch 6 taken 6753 times.
✓ Branch 7 taken 6753 times.
✓ Branch 8 taken 8628 times.
✓ Branch 9 taken 8628 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 15884 times.
✓ Branch 13 taken 16387 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 76685 times.
✓ Branch 17 taken 76685 times.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 1 times.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 1 times.
✓ Branch 22 taken 8746 times.
✓ Branch 23 taken 8746 times.
268775 if (i == 1) return this->component1();
1737
11/24
✓ Branch 0 taken 8038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6754 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2644 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6753 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8628 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 16387 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 76685 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 8746 times.
✗ Branch 23 not taken.
134639 if (i == 2) return this->expression();
1738 return nullptr;
1739 }
1740 /// @copybrief Node::replacechild()
1741 3 inline bool replacechild(const size_t i, Node* node) override final {
1742
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (i > 2) return false;
1743
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 Expression* expr = dynamic_cast<Expression*>(node);
1744
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (!expr) return false;
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (i == 0) mIdx0.reset(expr);
1746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (i == 1) mIdx1.reset(expr);
1747
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (i == 2) mExpression.reset(expr);
1748 3 expr->setParent(this);
1749 3 return true;
1750 }
1751
1752 /// @brief Access a const pointer to the first component being used as an
1753 /// abstract Expression
1754 /// @return A const pointer to the first component
1755 inline const Expression* component0() const { return mIdx0.get(); }
1756 /// @brief Access a const pointer to the second component being used as an
1757 /// abstract Expression
1758 /// @note This can be a nullptr for single indexing operations
1759 /// @return A const pointer to the second component
1760 inline const Expression* component1() const { return mIdx1.get(); }
1761 /// @brief Access a const pointer to the expression being indexed as an
1762 /// abstract Expression
1763 /// @return A const pointer to the expression
1764 inline const Expression* expression() const { return mExpression.get(); }
1765 /// @brief Query whether this ArrayUnpack operation must be a matrix
1766 /// indexing operation by checking the presence of a second
1767 /// component access.
1768 /// @note This method only guarantees that the indexing operation must be
1769 /// a matrix index. Single indexing is also valid for matrices and
1770 /// other multi dimensional containers
1771 /// @return True if this is a double indexing operation, only valid for
1772 /// matrices
1773 inline bool isMatrixIndex() const {
1774 // assumes that component0 is always valid
1775 return static_cast<bool>(this->component1());
1776 }
1777 private:
1778 Expression::UniquePtr mIdx0, mIdx1;
1779 Expression::UniquePtr mExpression;
1780 };
1781
1782 /// @brief ArrayPacks represent temporary container creations of arbitrary
1783 /// sizes, typically generated through the use of curly braces {}.
1784 struct ArrayPack : public Expression
1785 {
1786 using UniquePtr = std::unique_ptr<ArrayPack>;
1787
1788 /// @brief Construct a new ArrayPack with a single expression, transferring
1789 /// ownership of the expression to the ArrayPack and updating parent
1790 /// data on the expression. If the expression is a nullptr, it is
1791 /// ignored.
1792 /// @param expression The Expression to construct from
1793 ArrayPack(Expression* expression)
1794 : mExpressions() {
1795 this->append(expression);
1796 }
1797 /// @brief Construct a new ArrayPack transferring ownership of any
1798 /// provided arguments to the ArrayPack and updating parent data
1799 /// on the arguments.
1800 /// @param arguments ArrayPack arguments
1801 4068 ArrayPack(const std::vector<Expression*>& arguments)
1802
1/2
✓ Branch 1 taken 4068 times.
✗ Branch 2 not taken.
4068 : mExpressions() {
1803
1/2
✓ Branch 1 taken 4068 times.
✗ Branch 2 not taken.
4068 mExpressions.reserve(arguments.size());
1804
2/2
✓ Branch 0 taken 22538 times.
✓ Branch 1 taken 4068 times.
26606 for (Expression* arg : arguments) {
1805
1/2
✓ Branch 1 taken 22538 times.
✗ Branch 2 not taken.
22538 this->append(arg);
1806 }
1807 4068 }
1808 /// @brief Deep copy constructor for a ArrayPack, performing a deep copy
1809 /// on all held arguments, ensuring parent information is updated.
1810 /// @param other A const reference to another ArrayPack to deep copy
1811 1961 ArrayPack(const ArrayPack& other)
1812
1/2
✓ Branch 1 taken 1961 times.
✗ Branch 2 not taken.
1961 : mExpressions() {
1813
1/2
✓ Branch 1 taken 1961 times.
✗ Branch 2 not taken.
1961 mExpressions.reserve(other.mExpressions.size());
1814
2/2
✓ Branch 0 taken 10966 times.
✓ Branch 1 taken 1961 times.
12927 for (const Expression::UniquePtr& expr : other.mExpressions) {
1815
2/4
✓ Branch 1 taken 10966 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10966 times.
✗ Branch 5 not taken.
10966 this->append(expr->copy());
1816 }
1817 1961 }
1818 12058 ~ArrayPack() override = default;
1819
1820 /// @copybrief Node::copy()
1821
1/2
✓ Branch 2 taken 1961 times.
✗ Branch 3 not taken.
1961 ArrayPack* copy() const override final { return new ArrayPack(*this); }
1822 /// @copybrief Node::nodetype()
1823 126305 NodeType nodetype() const override { return Node::ArrayPackNode; }
1824 /// @copybrief Node::nodename()
1825 const char* nodename() const override { return "array pack"; }
1826 /// @copybrief Node::subname()
1827 const char* subname() const override { return "pack"; }
1828 /// @copybrief Node::basetype()
1829
3/6
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
73 const Expression* basetype() const override { return this; }
1830 /// @copybrief Node::children()
1831 206763 size_t children() const override final { return this->size(); }
1832 /// @copybrief Node::child()
1833
1/2
✓ Branch 0 taken 173280 times.
✗ Branch 1 not taken.
173280 const Expression* child(const size_t i) const override final {
1834
12/24
✓ Branch 0 taken 67854 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22138 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 56816 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 76537 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 158097 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 248525 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 173280 times.
✗ Branch 23 not taken.
860078 if (i >= mExpressions.size()) return nullptr;
1835 860078 return mExpressions[i].get();
1836 }
1837 /// @copybrief Node::replacechild()
1838 inline bool replacechild(const size_t i, Node* node) override final {
1839 if (mExpressions.size() <= i) return false;
1840 Expression* expr = dynamic_cast<Expression*>(node);
1841 mExpressions[i].reset(expr);
1842 mExpressions[i]->setParent(this);
1843 return true;
1844 }
1845
1846 /// @brief Alias for ArrayPack::children
1847 inline size_t size() const { return mExpressions.size(); }
1848 /// @brief Query whether this Expression list holds any valid expressions
1849 /// @return True if this node if empty, false otherwise
1850 inline bool empty() const { return mExpressions.empty(); }
1851 /// @brief Appends an argument to this ArrayPack, transferring ownership
1852 /// to the ArrayPack and updating parent data on the expression.
1853 /// If the expression is a nullptr, it is ignored.
1854 33504 inline void append(Expression* expr) {
1855
1/2
✓ Branch 0 taken 33504 times.
✗ Branch 1 not taken.
33504 if (expr) {
1856 33504 mExpressions.emplace_back(expr);
1857 33504 expr->setParent(this);
1858 }
1859 33504 }
1860 private:
1861 std::vector<Expression::UniquePtr> mExpressions;
1862 };
1863
1864 /// @brief Attributes represent any access to a primitive value, typically
1865 /// associated with the '@' symbol syntax. Note that the AST does not
1866 /// store any additional information on the given attribute other than
1867 /// its name and type, which together form a unique Attribute identifier
1868 /// known as the Attribute 'token'. A 'primitive value' in this instance
1869 /// refers to a value on an OpenVDB Volume or OpenVDB Points tree.
1870 /// @note The ExternalVariable AST node works in a similar way
1871 /// @note An Attribute is a complete "leaf-level" AST node. It has no children
1872 /// and nothing derives from it.
1873 struct Attribute : public Variable
1874 {
1875 using UniquePtr = std::unique_ptr<Attribute>;
1876
1877 /// @brief Construct a new Attribute with a given name and type. Optionally
1878 /// also mark it as inferred type creation (no type was directly
1879 /// specified)
1880 /// @param name The name of the attribute
1881 /// @param type The type of the attribute
1882 /// @param inferred Whether the provided type was directly specified
1883 /// (false).
1884 Attribute(const std::string& name, const tokens::CoreType type,
1885 const bool inferred = false)
1886
14/28
✓ Branch 1 taken 5675 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12055 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
22759 : Variable(name)
1887 , mType(type)
1888
14/28
✓ Branch 1 taken 5140 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
22759 , mTypeInferred(inferred) {}
1889 /// @brief Construct a new Attribute with a given name and type/token
1890 /// string, delegating construction to the above Attribute
1891 /// constructor.
1892 /// @param name The name of the attribute
1893 /// @param token The type/token string of the attribute
1894 /// @param inferred Whether the provided type was directly specified
1895 /// (false).
1896 Attribute(const std::string& name, const std::string& token,
1897 const bool inferred = false)
1898 : Attribute(name, tokens::tokenFromTypeString(token), inferred) {}
1899 /// @brief Deep copy constructor for a Attribute
1900 /// @note No parent information needs updating as an Attribute is a
1901 /// "leaf level" node (contains no children)
1902 /// @param other A const reference to another Attribute to deep copy
1903 Attribute(const Attribute& other)
1904
1/2
✓ Branch 1 taken 6086 times.
✗ Branch 2 not taken.
6086 : Variable(other)
1905 6086 , mType(other.mType)
1906 6086 , mTypeInferred(other.mTypeInferred) {}
1907 37634 ~Attribute() override = default;
1908
1909 /// @copybrief Node::copy()
1910 12172 Attribute* copy() const override final { return new Attribute(*this); }
1911 /// @copybrief Node::nodetype()
1912 554805 NodeType nodetype() const override { return Node::AttributeNode; }
1913 /// @copybrief Node::nodename()
1914 const char* nodename() const override { return "attribute"; }
1915 /// @copybrief Node::subname()
1916 const char* subname() const override { return "atr"; }
1917 /// @copybrief Node::basetype()
1918 const Variable* basetype() const override { return this; }
1919
1920 /// @brief Query whether this attribute was accessed via inferred syntax
1921 /// i.e. \@P or \@myattribute
1922 /// @return True if inferred syntax was used
1923
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 5996 times.
6207 inline bool inferred() const { return mTypeInferred; }
1924 /// @brief Access the type that was used to access this attribute
1925 /// @return The type used to access this attribute as a tokens::CoreType
1926
17/23
✓ Branch 0 taken 49136 times.
✓ Branch 1 taken 29844 times.
✓ Branch 2 taken 5085 times.
✓ Branch 3 taken 4979 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 5085 times.
✓ Branch 6 taken 5085 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5149 times.
✓ Branch 9 taken 4928 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 884 times.
✓ Branch 12 taken 4869712 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 11605 times.
✓ Branch 15 taken 1699 times.
✓ Branch 16 taken 89 times.
✓ Branch 17 taken 5085 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 4940 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 4940 times.
✗ Branch 24 not taken.
5014355 inline tokens::CoreType type() const { return mType; }
1927 /// @brief Get the access type as a front end AX type/token string
1928 /// @note This returns the associated token to the type, not necessarily
1929 /// equal to the OpenVDB type string
1930 /// @return A string representing the type/token
1931 inline std::string typestr() const {
1932 12100 return ast::tokens::typeStringFromToken(mType);
1933 }
1934 /// @brief Construct and return the full attribute token identifier. See
1935 /// Attribute::tokenFromNameType
1936 /// @return A string representing the attribute token.
1937 inline std::string tokenname() const {
1938
7/13
✓ Branch 2 taken 10149 times.
✓ Branch 3 taken 4189 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10147 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 142780 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 9860 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 5085 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 4940 times.
✗ Branch 18 not taken.
288671 return Attribute::tokenFromNameType(this->name(), this->type());
1939 }
1940
1941 /// @brief Static method returning the symbol associated with an Attribute
1942 /// access as defined by AX Grammar
1943 /// @return The '@' character as a char
1944 static inline char symbolseparator() { return '@'; }
1945 /// @brief Static method returning the full unique attribute token
1946 /// identifier by consolidating its name and type such that
1947 /// token = tokenstr + '\@' + name, where tokenstr is the AX type
1948 /// token as a string, converted from the provided CoreType.
1949 /// @note This identifier is unique for accesses to the same attribute
1950 /// @note Due to inferred and single character accesses in AX, this return
1951 /// value does not necessarily represent the original syntax used to
1952 /// access this attribute. For example, \@myattrib will be stored
1953 /// and returned as float\@myattrib.
1954 /// @param name The name of the attribute
1955 /// @param type The CoreType of the attribute
1956 /// @return A string representing the attribute token.
1957 static inline std::string
1958 431516 tokenFromNameType(const std::string& name, const tokens::CoreType type) {
1959 863032 return ast::tokens::typeStringFromToken(type) +
1960 431516 Attribute::symbolseparator() + name;
1961 }
1962 /// @brief Static method which splits a valid attribute token into its name
1963 /// and type counterparts. If the token cannot be split, neither
1964 /// name or type are updated and false is returned.
1965 /// @param token The token to split.
1966 /// @param name Set to the second part of the attribute token,
1967 /// representing the name. If a nullptr, it is ignored
1968 /// @param type Set to the first part of the attribute token,
1969 /// representing the type. If a nullptr, it is ignored. Note
1970 /// that this can be empty if the attribute token has an
1971 /// inferred type or a single character.
1972 /// @return True if the provided attribute token could be split
1973 static inline bool
1974 45884 nametypeFromToken(const std::string& token, std::string* name, std::string* type) {
1975 45884 const size_t at = token.find(symbolseparator());
1976
2/2
✓ Branch 0 taken 45807 times.
✓ Branch 1 taken 77 times.
45884 if (at == std::string::npos) return false;
1977
1/2
✓ Branch 0 taken 45807 times.
✗ Branch 1 not taken.
45807 if (type) {
1978
2/2
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 45717 times.
91614 *type = token.substr(0, at);
1979
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 45717 times.
45807 if (type->empty()) {
1980 180 *type = ast::tokens::typeStringFromToken(tokens::CoreType::FLOAT);
1981 }
1982 }
1983
1/2
✓ Branch 0 taken 45807 times.
✗ Branch 1 not taken.
91614 if (name) *name = token.substr(at + 1, token.size());
1984 return true;
1985 }
1986 private:
1987 const tokens::CoreType mType;
1988 const bool mTypeInferred;
1989 };
1990
1991 /// @brief ExternalVariable represent any access to external (custom) data,
1992 /// typically associated with the '$' symbol syntax. Note that the AST
1993 /// does not store any additional information on the given external
1994 /// other than its name and type, which together form a unique external
1995 /// identifier known as the ExternalVariable 'token'. This token is used
1996 /// by the compiler to map user provided values to these external
1997 /// values.
1998 /// @note The Attribute AST node works in a similar way
1999 /// @note An ExternalVariable is a complete "leaf-level" AST node. It has no
2000 /// children and nothing derives from it.
2001 struct ExternalVariable : public Variable
2002 {
2003 using UniquePtr = std::unique_ptr<ExternalVariable>;
2004
2005 /// @brief Construct a new ExternalVariable with a given name and type
2006 /// @param name The name of the attribute
2007 /// @param type The type of the attribute
2008 ExternalVariable(const std::string& name, const tokens::CoreType type)
2009
1/2
✓ Branch 1 taken 181 times.
✗ Branch 2 not taken.
181 : Variable(name)
2010 181 , mType(type) {}
2011 /// @brief Construct a new ExternalVariable with a given name and type/token
2012 /// string, delegating construction to the above ExternalVariable
2013 /// constructor.
2014 /// @param name The name of the attribute
2015 /// @param token The type/token string of the attribute
2016 ExternalVariable(const std::string& name, const std::string& token)
2017 : ExternalVariable(name, tokens::tokenFromTypeString(token)) {}
2018 /// @brief Deep copy constructor for a ExternalVariable
2019 /// @note No parent information needs updating as an ExternalVariable is a
2020 /// "leaf level" node (contains no children)
2021 /// @param other A const reference to another ExternalVariable to deep
2022 /// copy
2023 ExternalVariable(const ExternalVariable& other)
2024
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 : Variable(other)
2025 42 , mType(other.mType) {}
2026 480 ~ExternalVariable() override = default;
2027
2028 /// @copybrief Node::copy()
2029 42 ExternalVariable* copy() const override final {
2030 84 return new ExternalVariable(*this);
2031 }
2032 /// @copybrief Node::nodetype()
2033 1338 NodeType nodetype() const override { return Node::ExternalVariableNode; }
2034 /// @copybrief Node::nodename()
2035 const char* nodename() const override { return "external"; }
2036 /// @copybrief Node::subname()
2037 const char* subname() const override { return "ext"; }
2038 /// @copybrief Node::basetype()
2039 const Variable* basetype() const override { return this; }
2040
2041 /// @brief Access the type that was used to access this external variable
2042 /// @return The type used to access this external as a tokens::CoreType
2043
2/3
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
94 inline tokens::CoreType type() const { return mType; }
2044 /// @brief Get the access type as a front end AX type/token string
2045 /// @note This returns the associated token to the type, not necessarily
2046 /// equal to the OpenVDB type string
2047 /// @return A string representing the type/token
2048 inline std::string typestr() const {
2049 86 return ast::tokens::typeStringFromToken(mType);
2050 }
2051 /// @brief Construct and return the full external token identifier. See
2052 /// ExternalVariable::tokenFromNameType
2053 /// @return A string representing the external variable token.
2054 inline const std::string tokenname() const {
2055 77 return ExternalVariable::tokenFromNameType(this->name(), this->type());
2056 }
2057
2058 /// @brief Static method returning the symbol associated with an
2059 /// ExternalVariable access as defined by AX Grammar
2060 /// @return The '$' character as a char
2061 static inline char symbolseparator() { return '$'; }
2062 /// @brief Static method returning the full unique external token
2063 /// identifier by consolidating its name and type such that
2064 /// token = tokenstr + '$' + name, where tokenstr is the AX type
2065 /// token as a string, converted from the provided CoreType.
2066 /// @note This identifier is unique for accesses to the same external
2067 /// @note Due to inferred and single character accesses in AX, this return
2068 /// value does not necessarily represent the original syntax used to
2069 /// access this external. For example, v$data will be stored and
2070 /// returned as vec3f$data.
2071 /// @param name The name of the external
2072 /// @param type The CoreType of the external
2073 /// @return A string representing the external token.
2074 static inline std::string
2075 77 tokenFromNameType(const std::string& name, const tokens::CoreType type) {
2076 154 return ast::tokens::typeStringFromToken(type) +
2077 77 ExternalVariable::symbolseparator() + name;
2078 }
2079 /// @brief Static method which splits a valid external token into its name
2080 /// and type counterparts. If the token cannot be split, neither
2081 /// name or type are updated and false is returned.
2082 /// @param token The token to split.
2083 /// @param name Set to the second part of the external token,
2084 /// representing the name. If a nullptr, it is ignored
2085 /// @param type Set to the first part of the external token,
2086 /// representing the type. If a nullptr, it is ignored. Note
2087 /// that this can be empty if the external token has an
2088 /// inferred type or a single character.
2089 /// @return True if the provided external token could be split
2090 static inline bool
2091 10222 nametypeFromToken(const std::string& token, std::string* name, std::string* type) {
2092 10222 const size_t at = token.find(symbolseparator());
2093
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 10145 times.
10222 if (at == std::string::npos) return false;
2094
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 if (type) {
2095
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 77 times.
154 *type = token.substr(0, at);
2096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 if (type->empty()) {
2097 *type = ast::tokens::typeStringFromToken(tokens::CoreType::FLOAT);
2098 }
2099 }
2100
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
154 if (name) *name = token.substr(at + 1, token.size());
2101 return true;
2102 }
2103 private:
2104 const tokens::CoreType mType;
2105 };
2106
2107 /// @brief Local AST nodes represent a single accesses to a local variable.
2108 /// The only store the name of the variable being accessed.
2109 /// @note A Local is a complete "leaf-level" AST node. It has no children and
2110 /// nothing derives from it.
2111 4701 struct Local : public Variable
2112 {
2113 using UniquePtr = std::unique_ptr<Local>;
2114
2115 /// @brief Construct a Local with a given name
2116 /// @param name The name of the local variable being accessed
2117 Local(const std::string& name)
2118
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
11417 : Variable(name) {}
2119 33146 ~Local() override = default;
2120
2121 /// @copybrief Node::copy()
2122 9402 Local* copy() const override final { return new Local(*this); }
2123 /// @copybrief Node::nodetype()
2124 554054 NodeType nodetype() const override { return Node::LocalNode; }
2125 /// @copybrief Node::nodename()
2126 const char* nodename() const override { return "local"; }
2127 /// @copybrief Node::subname()
2128 const char* subname() const override { return "lcl"; }
2129 /// @copybrief Node::basetype()
2130 const Variable* basetype() const override { return this; }
2131 };
2132
2133 /// @brief DeclareLocal AST nodes symbolize a single type declaration of a
2134 /// local variable. These store the local variables that They also however store its
2135 /// specified type. These have the important distinction of representing
2136 /// the initial creation and allocation of a variable, in comparison to
2137 /// a Local node which only represents access.
2138 struct DeclareLocal : public Statement
2139 {
2140 using UniquePtr = std::unique_ptr<DeclareLocal>;
2141
2142 /// @brief Construct a new DeclareLocal with a given name and type
2143 /// @param type The type of the declaration
2144 /// @param local The local variable being declared
2145 /// @param init The initialiser expression of the local
2146 3801 DeclareLocal(const tokens::CoreType type, Local* local, Expression* init = nullptr)
2147 3801 : mType(type)
2148 , mLocal(local)
2149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3801 times.
3801 , mInit(init) {
2150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3801 times.
3801 assert(mLocal);
2151
1/2
✓ Branch 1 taken 3801 times.
✗ Branch 2 not taken.
3801 mLocal->setParent(this);
2152
3/4
✓ Branch 0 taken 2967 times.
✓ Branch 1 taken 834 times.
✓ Branch 3 taken 2967 times.
✗ Branch 4 not taken.
3801 if (mInit) mInit->setParent(this);
2153 3801 }
2154 /// @brief Deep copy constructor for a DeclareLocal
2155 /// @note No parent information needs updating as an DeclareLocal is a
2156 /// "leaf level" node (contains no children)
2157 /// @param other A const reference to another DeclareLocal to deep copy
2158 1598 DeclareLocal(const DeclareLocal& other)
2159 1598 : mType(other.mType)
2160 , mLocal(other.mLocal->copy())
2161
3/4
✓ Branch 1 taken 1427 times.
✓ Branch 2 taken 171 times.
✓ Branch 4 taken 1427 times.
✗ Branch 5 not taken.
1598 , mInit(other.hasInit() ? other.mInit->copy() : nullptr) {
2162
1/2
✓ Branch 1 taken 1598 times.
✗ Branch 2 not taken.
1598 mLocal->setParent(this);
2163
3/4
✓ Branch 0 taken 1427 times.
✓ Branch 1 taken 171 times.
✓ Branch 3 taken 1427 times.
✗ Branch 4 not taken.
1598 if (mInit) mInit->setParent(this);
2164 1598 }
2165
2/2
✓ Branch 0 taken 4394 times.
✓ Branch 1 taken 1005 times.
21596 ~DeclareLocal() override = default;
2166
2167 /// @copybrief Node::copy()
2168
1/2
✓ Branch 2 taken 1598 times.
✗ Branch 3 not taken.
1598 DeclareLocal* copy() const override final { return new DeclareLocal(*this); }
2169 /// @copybrief Node::nodetype()
2170 108559 NodeType nodetype() const override { return Node::DeclareLocalNode; }
2171 /// @copybrief Node::nodename()
2172 const char* nodename() const override { return "declaration"; }
2173 /// @copybrief Node::subname()
2174 const char* subname() const override { return "dcl"; }
2175 /// @copybrief Node::basetype()
2176
1/4
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
116 const Statement* basetype() const override { return this; }
2177 /// @copybrief Node::children()
2178 29389 size_t children() const override final { return 2; }
2179 /// @copybrief Node::child()
2180 19626 const Expression* child(const size_t i) const override final {
2181
16/22
✓ Branch 0 taken 11494 times.
✓ Branch 1 taken 11504 times.
✓ Branch 2 taken 3284 times.
✓ Branch 3 taken 3284 times.
✓ Branch 4 taken 3310 times.
✓ Branch 5 taken 3310 times.
✓ Branch 6 taken 3284 times.
✓ Branch 7 taken 3284 times.
✓ Branch 8 taken 11149 times.
✓ Branch 9 taken 11149 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 5787 times.
✓ Branch 13 taken 5787 times.
✓ Branch 14 taken 7 times.
✓ Branch 15 taken 7 times.
✓ Branch 16 taken 66373 times.
✓ Branch 17 taken 66348 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
209361 if (i == 0) return this->local();
2182
8/22
✓ Branch 0 taken 11504 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3284 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3310 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3284 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11149 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 5787 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 66348 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
104673 if (i == 1) return this->init();
2183 return nullptr;
2184 }
2185 /// @copybrief Node::replacechild()
2186 inline bool replacechild(const size_t i, Node* node) override final {
2187 if (i > 1) return false;
2188 if (i == 0) {
2189 Local* local = dynamic_cast<Local*>(node);
2190 if (!local) return false;
2191 mLocal.reset(local);
2192 mLocal->setParent(this);
2193 }
2194 else {
2195 Expression* init = dynamic_cast<Expression*>(node);
2196 if (!init) return false;
2197 mInit.reset(init);
2198 mInit->setParent(this);
2199 }
2200 return true;
2201 }
2202
2203 /// @brief Access the type that was specified at which to create the given
2204 /// local
2205 /// @return The declaration type
2206
3/3
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 3452 times.
4004 inline tokens::CoreType type() const { return mType; }
2207 /// @brief Get the declaration type as a front end AX type/token string
2208 /// @note This returns the associated token to the type, not necessarily
2209 /// equal to the OpenVDB type string
2210 /// @return A string representing the type/token
2211 inline std::string typestr() const {
2212 8 return ast::tokens::typeStringFromToken(mType);
2213 }
2214 /// @brief Query if this declaration has an initialiser
2215 /// @return True if an initialiser exists, false otherwise
2216 inline bool hasInit() const { return static_cast<bool>(this->init()); }
2217
2218 /// @brief Access a const pointer to the Local
2219 /// @return A const pointer to the local
2220 const Local* local() const { return mLocal.get(); }
2221 /// @brief Access a const pointer to the initialiser
2222 /// @return A const pointer to the initialiser
2223 const Expression* init() const { return mInit.get(); }
2224
2225 private:
2226 const tokens::CoreType mType;
2227 Local::UniquePtr mLocal; // could be Variable for attribute declaration
2228 Expression::UniquePtr mInit;
2229 };
2230
2231
2232 /// @brief A Value (literal) AST node holds either literal text or absolute
2233 /// value information on all numerical, string and boolean constants.
2234 /// A single instance of a Value is templated on the requested scalar,
2235 /// boolean or string type. If scalar or boolean value is constructed
2236 /// from a string (as typically is the case in the parser), the value is
2237 /// automatically converted to its numerical representation. If this
2238 /// fails, the original text is stored instead.
2239 /// @note All numerical values are stored as their highest possible precision
2240 /// type to support overflowing without storing the original string
2241 /// data. The original string data is only required if the value is too
2242 /// large to be stored in these highest precision types (usually a
2243 /// uint64_t for scalars or double for floating points).
2244 /// @note Numerical values are guaranteed to be positive (if constructed from
2245 /// the AX parser). Negative values are represented by a combination of
2246 /// a UnaryOperator holding a Value AST node.
2247 /// @note Note that Value AST nodes representing strings are specialized and
2248 /// are guranteed to be "well-formed" (there is no numerical conversion)
2249 /// @note A Value is a complete "leaf-level" AST node. It has no children and
2250 /// nothing derives from it.
2251 template <typename T>
2252 struct Value : public ValueBase
2253 {
2254 using UniquePtr = std::unique_ptr<Value<T>>;
2255
2256 using Type = T;
2257 /// @brief Integers and Floats store their value as ContainerType, which is
2258 /// guaranteed to be at least large enough to represent the maximum
2259 /// possible supported type for the requested precision.
2260 using ContainerType = typename std::conditional<
2261 std::is_integral<T>::value, uint64_t, T>::type;
2262
2263 /// @brief The list of supported numerical constants.
2264 /// @note Strings are specialized and handled separately
2265 static constexpr bool IsSupported =
2266 std::is_same<T, bool>::value ||
2267 std::is_same<T, int16_t>::value ||
2268 std::is_same<T, int32_t>::value ||
2269 std::is_same<T, int64_t>::value ||
2270 std::is_same<T, float>::value ||
2271 std::is_same<T, double>::value;
2272 static_assert(IsSupported, "Incompatible ast::Value node instantiated.");
2273
2274 /// @brief Directly construct a Value from a source integer, float or
2275 /// boolean, guaranteeing valid construction. Note that the provided
2276 /// argument should not be negative
2277 33832 Value(const ContainerType value)
2278
9/14
✗ Branch 0 not taken.
✓ Branch 1 taken 11906 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11531 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 417 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 8663 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 473 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 839 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
33830 : mValue(value) {}
2279 /// @brief Deep copy constructor for a Value
2280 /// @note No parent information needs updating as a Value is a "leaf
2281 /// level" node (contains no children)
2282 /// @param other A const reference to another Value to deep copy
2283 16297 Value(const Value<T>& other)
2284 16297 : mValue(other.mValue) {}
2285 101090 ~Value() override = default;
2286
2287 /// @copybrief Node::copy()
2288 32594 Value<Type>* copy() const override final { return new Value<Type>(*this); }
2289 /// @copybrief Node::nodetype()
2290 2247718 NodeType nodetype() const override {
2291 if (std::is_same<T, bool>::value) return Node::ValueBoolNode;
2292 if (std::is_same<T, int16_t>::value) return Node::ValueInt16Node;
2293 if (std::is_same<T, int32_t>::value) return Node::ValueInt32Node;
2294 if (std::is_same<T, int64_t>::value) return Node::ValueInt64Node;
2295 if (std::is_same<T, float>::value) return Node::ValueFloatNode;
2296 if (std::is_same<T, double>::value) return Node::ValueDoubleNode;
2297 }
2298 /// @copybrief Node::nodename()
2299 const char* nodename() const override {
2300 if (std::is_same<T, bool>::value) return "boolean literal";
2301 if (std::is_same<T, int16_t>::value) return "int16 literal";
2302 if (std::is_same<T, int32_t>::value) return "int32 literal";
2303 if (std::is_same<T, int64_t>::value) return "int64 literal";
2304 if (std::is_same<T, float>::value) return "float (32bit) literal";
2305 if (std::is_same<T, double>::value) return "double (64bit) literal";
2306 }
2307 /// @copybrief Node::subname()
2308 const char* subname() const override {
2309 if (std::is_same<T, bool>::value) return "bool";
2310 if (std::is_same<T, int16_t>::value) return "i16";
2311 if (std::is_same<T, int32_t>::value) return "i32";
2312 if (std::is_same<T, int64_t>::value) return "i64";
2313 if (std::is_same<T, float>::value) return "flt";
2314 if (std::is_same<T, double>::value) return "dbl";
2315 }
2316 /// @copybrief Node::basetype()
2317 const ValueBase* basetype() const override { return this; }
2318
2319 /// @brief Access the value as its stored type
2320 /// @return The value as its stored ContainerType
2321
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 396 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8173 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8577 inline ContainerType asContainerType() const { return mValue; }
2322 /// @brief Access the value as its requested (templated) type
2323 /// @return The value as its templed type T
2324
6/12
✓ Branch 0 taken 11899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11472 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 292 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 27 times.
✗ Branch 11 not taken.
32993 inline T value() const { return static_cast<T>(mValue); }
2325
2326 private:
2327 // A container of a max size defined by LiteralValueContainer to hold values
2328 // which may be out of scope. This is only used for warnings
2329 const ContainerType mValue;
2330 };
2331
2332 /// @brief Specialization of Values for strings
2333 template <>
2334 struct Value<std::string> : public ValueBase
2335 {
2336 using UniquePtr = std::unique_ptr<Value<std::string>>;
2337
2338 using Type = std::string;
2339 /// @brief Construct a new Value string from a string
2340 /// @param value The string to copy onto this Value
2341
1/2
✓ Branch 1 taken 654 times.
✗ Branch 2 not taken.
654 Value(const Type& value) : mValue(value) {}
2342 /// @brief Deep copy constructor for a Value string
2343 /// @note No parent information needs updating as a Value is a "leaf
2344 /// level" node (contains no children)
2345 /// @param other A const reference to another Value string to deep copy
2346
1/2
✓ Branch 1 taken 320 times.
✗ Branch 2 not taken.
320 Value(const Value<Type>& other) : mValue(other.mValue) {}
2347 1992 ~Value() override = default;
2348
2349 640 Value<Type>* copy() const override final { return new Value<Type>(*this); }
2350 13905 NodeType nodetype() const override { return Node::ValueStrNode; }
2351 const char* nodename() const override { return "string value"; }
2352 const char* subname() const override { return "str"; }
2353 const ValueBase* basetype() const override { return this; }
2354
2355 /// @brief Access the string
2356 /// @return A const reference to the string
2357
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 inline const std::string& value() const { return mValue; }
2358 private:
2359 const Type mValue;
2360 };
2361
2362 } // namespace ast
2363 } // namespace ax
2364
2365 } // namespace OPENVDB_VERSION_NAME
2366 } // namespace openvdb
2367
2368 #endif // OPENVDB_AX_AST_HAS_BEEN_INCLUDED
2369
2370