GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/compiler/Compiler.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 32 35 91.4%
Functions: 11 11 100.0%
Branches: 45 88 51.1%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file compiler/Compiler.h
5 ///
6 /// @authors Nick Avramoussis, Francisco Gochez, Richard Jones
7 ///
8 /// @brief The OpenVDB AX Compiler class provides methods to generate
9 /// AX executables from a provided AX AST (or directly from a given
10 /// string). The class object exists to cache various structures,
11 /// primarily LLVM constructs, which benefit from existing across
12 /// additional compilation runs.
13 ///
14
15 #ifndef OPENVDB_AX_COMPILER_HAS_BEEN_INCLUDED
16 #define OPENVDB_AX_COMPILER_HAS_BEEN_INCLUDED
17
18 #include "CompilerOptions.h"
19 #include "CustomData.h"
20 #include "Logger.h"
21
22 #include "openvdb_ax/ax.h" // backward compat support for initialize()
23 #include "openvdb_ax/ast/Parse.h"
24
25 #include <openvdb/version.h>
26
27 #include <memory>
28 #include <sstream>
29
30 // forward
31 namespace llvm {
32 class LLVMContext;
33 }
34
35 namespace openvdb {
36 OPENVDB_USE_VERSION_NAMESPACE
37 namespace OPENVDB_VERSION_NAME {
38
39 namespace ax {
40
41 namespace codegen {
42 // forward
43 class FunctionRegistry;
44 }
45
46 /// @brief The compiler class. This holds an llvm context and set of compiler
47 /// options, and constructs executable objects (e.g. PointExecutable or
48 /// VolumeExecutable) from a syntax tree or snippet of code.
49 class OPENVDB_AX_API Compiler
50 {
51 public:
52
53 using Ptr = std::shared_ptr<Compiler>;
54 using UniquePtr = std::unique_ptr<Compiler>;
55
56 /// @brief Construct a compiler object with given settings
57 /// @param options CompilerOptions object with various settings
58 Compiler(const CompilerOptions& options = CompilerOptions());
59
60
1/2
✓ Branch 0 taken 1480 times.
✗ Branch 1 not taken.
1480 ~Compiler() = default;
61
62 /// @brief Static method for creating Compiler objects
63 static UniquePtr create(const CompilerOptions& options = CompilerOptions());
64
65 /// @brief Compile a given AST into an executable object of the given type.
66 /// @param syntaxTree An abstract syntax tree to compile
67 /// @param logger Logger for errors and warnings during compilation, this
68 /// should be linked to an ast::Tree and populated with AST node + line
69 /// number mappings for this Tree, e.g. during ast::parse(). This Tree can
70 /// be different from the syntaxTree argument.
71 /// @param data Optional external/custom data which is to be referenced by
72 /// the executable object. It allows one to reference data held elsewhere,
73 /// such as inside of a DCC, from inside the AX code
74 /// @note If the logger has not been populated with AST node and line
75 /// mappings, all messages will appear without valid line and column
76 /// numbers.
77 template <typename ExecutableT>
78 typename ExecutableT::Ptr
79 compile(const ast::Tree& syntaxTree,
80 Logger& logger,
81 const CustomData::Ptr data = CustomData::Ptr());
82
83 /// @brief Compile a given snippet of AX code into an executable object of
84 /// the given type.
85 /// @param code A string of AX code
86 /// @param logger Logger for errors and warnings during compilation, will be
87 /// cleared of existing data
88 /// @param data Optional external/custom data which is to be referenced by
89 /// the executable object. It allows one to reference data held elsewhere,
90 /// such as inside of a DCC, from inside the AX code
91 /// @note If compilation is unsuccessful, will return nullptr. Logger can
92 /// then be queried for errors.
93 template <typename ExecutableT>
94 typename ExecutableT::Ptr
95 8 compile(const std::string& code,
96 Logger& logger,
97 const CustomData::Ptr data = CustomData::Ptr())
98 {
99 8 logger.clear();
100 8 const ast::Tree::ConstPtr syntaxTree = ast::parse(code.c_str(), logger);
101
3/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
20 if (syntaxTree) return compile<ExecutableT>(*syntaxTree, logger, data);
102 else return nullptr;
103 }
104
105 /// @brief Compile a given snippet of AX code into an executable object of
106 /// the given type.
107 /// @param code A string of AX code
108 /// @param data Optional external/custom data which is to be referenced by
109 /// the executable object. It allows one to reference data held elsewhere,
110 /// such as inside of a DCC, from inside the AX code
111 /// @note Parser errors are handled separately from compiler errors.
112 /// Each are collected and produce runtime errors.
113 template <typename ExecutableT>
114 typename ExecutableT::Ptr
115 83 compile(const std::string& code,
116 const CustomData::Ptr data = CustomData::Ptr())
117 {
118 58 std::vector<std::string> errors;
119
3/8
✓ Branch 3 taken 83 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 83 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 83 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
357 openvdb::ax::Logger logger(
120 32 [&errors] (const std::string& error) {
121
1/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 errors.emplace_back(error + "\n");
122 },
123 [] (const std::string&) {} // ignore warnings
124 );
125
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 const ast::Tree::ConstPtr syntaxTree = ast::parse(code.c_str(), logger);
126
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 73 times.
83 if (!errors.empty()) {
127
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
20 std::ostringstream os;
128
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
30 for (const auto& e : errors) os << e << "\n";
129
2/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
50 OPENVDB_THROW(AXSyntaxError, os.str());
130 }
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 assert(syntaxTree);
132
6/6
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 10 times.
162 typename ExecutableT::Ptr exe = this->compile<ExecutableT>(*syntaxTree, logger, data);
133
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 58 times.
64 if (!errors.empty()) {
134
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
12 std::ostringstream os;
135
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
18 for (const auto& e : errors) os << e << "\n";
136
2/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
30 OPENVDB_THROW(AXCompilerError, os.str());
137 }
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 assert(exe);
139 58 return exe;
140 }
141
142 /// @brief Compile a given AST into an executable object of the given type.
143 /// @param syntaxTree An abstract syntax tree to compile
144 /// @param data Optional external/custom data which is to be referenced by
145 /// the executable object. It allows one to reference data held elsewhere,
146 /// such as inside of a DCC, from inside the AX code
147 /// @note Any errors encountered are collected into a single runtime error
148 template <typename ExecutableT>
149 typename ExecutableT::Ptr
150 2 compile(const ast::Tree& syntaxTree,
151 const CustomData::Ptr data = CustomData::Ptr())
152 {
153 std::vector<std::string> errors;
154
2/6
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
8 openvdb::ax::Logger logger(
155 4 [&errors] (const std::string& error) {
156
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 errors.emplace_back(error + "\n");
157 },
158 [] (const std::string&) {} // ignore warnings
159 );
160
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
6 auto exe = compile<ExecutableT>(syntaxTree, logger, data);
161
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!errors.empty()) {
162
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 std::ostringstream os;
163
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
6 for (const auto& e : errors) os << e << "\n";
164
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
10 OPENVDB_THROW(AXCompilerError, os.str());
165 }
166 assert(exe);
167 return exe;
168 }
169
170 /// @brief Sets the compiler's function registry object.
171 /// @param functionRegistry A unique pointer to a FunctionRegistry object.
172 /// The compiler will take ownership of the registry that was passed in.
173 /// @todo Perhaps allow one to register individual functions into this
174 /// class rather than the entire registry at once, and/or allow one to
175 /// extract a pointer to the registry and update it manually.
176 void setFunctionRegistry(std::unique_ptr<codegen::FunctionRegistry>&& functionRegistry);
177
178 ///////////////////////////////////////////////////////////////////////////
179
180 private:
181 template <typename ExeT, typename GenT>
182 typename ExeT::Ptr
183 compile(const ast::Tree& tree,
184 const std::string& moduleName,
185 const std::vector<std::string>& functions,
186 CustomData::Ptr data,
187 Logger& logger);
188
189 private:
190 std::shared_ptr<llvm::LLVMContext> mContext;
191 const CompilerOptions mCompilerOptions;
192 std::shared_ptr<codegen::FunctionRegistry> mFunctionRegistry;
193 };
194
195
196 } // namespace ax
197 } // namespace OPENVDB_VERSION_NAME
198 } // namespace openvdb
199
200 #endif // OPENVDB_AX_COMPILER_HAS_BEEN_INCLUDED
201
202