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 |