Skip to content

Commit 25acbfb

Browse files
authored
Merge pull request #1346 from Idclip/ax_improvements
Various AX improvements
2 parents 519f0a7 + 3ef01fd commit 25acbfb

File tree

17 files changed

+144
-88
lines changed

17 files changed

+144
-88
lines changed

openvdb_ax/openvdb_ax/ast/Parse.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,15 @@ extern void axerror (openvdb::ax::ast::Tree**, char const *s) {
3636
}
3737

3838
openvdb::ax::ast::Tree::ConstPtr
39-
openvdb::ax::ast::parse(const char* code, openvdb::ax::Logger& logger)
39+
openvdb::ax::ast::parse(const char* code,
40+
openvdb::ax::Logger& logger)
4041
{
4142
std::lock_guard<std::mutex> lock(sInitMutex);
4243
axlog = &logger; // for lexer errs
4344
logger.setSourceCode(code);
4445

46+
const size_t err = logger.errors();
47+
4548
// reset all locations
4649
axlloc.first_line = axlloc.last_line = 1;
4750
axlloc.first_column = axlloc.last_column = 1;
@@ -56,6 +59,8 @@ openvdb::ax::ast::parse(const char* code, openvdb::ax::Logger& logger)
5659

5760
ax_delete_buffer(buffer);
5861

62+
if (logger.errors() > err) ptr.reset();
63+
5964
logger.setSourceTree(ptr);
6065
return ptr;
6166
}

openvdb_ax/openvdb_ax/ast/Parse.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,35 @@ namespace OPENVDB_VERSION_NAME {
2323
namespace ax {
2424
namespace ast {
2525

26-
/// @brief Construct an abstract syntax tree from a code snippet. If the code is
27-
/// not well formed, as defined by the AX grammar, this will simply return
28-
/// nullptr, with the logger collecting the errors.
26+
/// @brief Construct an abstract syntax tree from a code snippet.
27+
/// @details This method parses the provided null terminated code snippet and
28+
/// attempts to construct a complete abstract syntax tree (AST) which can be
29+
/// passed to the AX Compiler. If the code is not well formed (as defined by
30+
/// the AX grammar) a nullptr is returned and instances of any errors
31+
/// encoutered are stored to the provided logger.
2932
/// @note The returned AST is const as the logger uses this to determine line
30-
/// and column numbers of errors/warnings in later stages. If you need to
31-
/// modify the tree, take a copy.
33+
/// and column numbers of errors/warnings in later stages. If you need to
34+
/// modify the tree, take a copy.
3235
///
33-
/// @return A shared pointer to a valid const AST, or nullptr if errored.
36+
/// @return A shared pointer to a valid const AST. Can be a nullptr on error.
37+
/// @todo In the future it may be useful for ::parse to return as much of
38+
/// the valid AST that exists.
3439
///
3540
/// @param code The code to parse
3641
/// @param logger The logger to collect syntax errors
3742
///
3843
OPENVDB_AX_API openvdb::ax::ast::Tree::ConstPtr
3944
parse(const char* code, ax::Logger& logger);
4045

41-
/// @brief Construct an abstract syntax tree from a code snippet.
42-
/// A runtime exception will be thrown with the first syntax error.
46+
/// @brief Construct an abstract syntax tree from a code snippet.
47+
/// @details A runtime exception will be thrown with the first syntax error.
4348
///
4449
/// @return A shared pointer to a valid AST.
4550
///
4651
/// @param code The code to parse
4752
///
48-
OPENVDB_AX_API openvdb::ax::ast::Tree::Ptr parse(const char* code);
53+
OPENVDB_AX_API openvdb::ax::ast::Tree::Ptr
54+
parse(const char* code);
4955

5056
} // namespace ast
5157
} // namespace ax

openvdb_ax/openvdb_ax/ax.cc

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#include "ax.h"
55
#include "ast/AST.h"
6-
#include "compiler/Logger.h"
76
#include "compiler/Compiler.h"
87
#include "compiler/PointExecutable.h"
98
#include "compiler/VolumeExecutable.h"
@@ -27,23 +26,16 @@ namespace ax {
2726

2827
void run(const char* ax, openvdb::GridBase& grid, const AttributeBindings& bindings)
2928
{
30-
// Construct a logger that will output errors to cerr and suppress warnings
31-
openvdb::ax::Logger logger;
3229
// Construct a generic compiler
3330
openvdb::ax::Compiler compiler;
34-
// Parse the provided code and produce an abstract syntax tree
35-
// @note Throws with parser errors if invalid. Parsable code does not
36-
// necessarily equate to compilable code
37-
const openvdb::ax::ast::Tree::ConstPtr
38-
ast = openvdb::ax::ast::parse(ax, logger);
39-
if (!ast) return;
4031

4132
if (grid.isType<points::PointDataGrid>()) {
4233
// Compile for Point support and produce an executable
4334
// @note Throws compiler errors on invalid code. On success, returns
4435
// the executable which can be used multiple times on any inputs
4536
const openvdb::ax::PointExecutable::Ptr exe =
46-
compiler.compile<openvdb::ax::PointExecutable>(*ast, logger);
37+
compiler.compile<openvdb::ax::PointExecutable>(ax);
38+
assert(exe);
4739

4840
//Set the attribute bindings
4941
exe->setAttributeBindings(bindings);
@@ -56,7 +48,9 @@ void run(const char* ax, openvdb::GridBase& grid, const AttributeBindings& bindi
5648
// @note Throws compiler errors on invalid code. On success, returns
5749
// the executable which can be used multiple times on any inputs
5850
const openvdb::ax::VolumeExecutable::Ptr exe =
59-
compiler.compile<openvdb::ax::VolumeExecutable>(*ast, logger);
51+
compiler.compile<openvdb::ax::VolumeExecutable>(ax);
52+
assert(exe);
53+
6054
// Set the attribute bindings
6155
exe->setAttributeBindings(bindings);
6256
// Execute on the provided numerical grid
@@ -78,23 +72,17 @@ void run(const char* ax, openvdb::GridPtrVec& grids, const AttributeBindings& bi
7872
"a single invocation of ax::run()");
7973
}
8074
}
81-
// Construct a logger that will output errors to cerr and suppress warnings
82-
openvdb::ax::Logger logger;
8375
// Construct a generic compiler
8476
openvdb::ax::Compiler compiler;
85-
// Parse the provided code and produce an abstract syntax tree
86-
// @note Throws with parser errors if invalid. Parsable code does not
87-
// necessarily equate to compilable code
88-
const openvdb::ax::ast::Tree::ConstPtr
89-
ast = openvdb::ax::ast::parse(ax, logger);
90-
if (!ast) return;
9177

9278
if (points) {
9379
// Compile for Point support and produce an executable
9480
// @note Throws compiler errors on invalid code. On success, returns
9581
// the executable which can be used multiple times on any inputs
9682
const openvdb::ax::PointExecutable::Ptr exe =
97-
compiler.compile<openvdb::ax::PointExecutable>(*ast, logger);
83+
compiler.compile<openvdb::ax::PointExecutable>(ax);
84+
assert(exe);
85+
9886
//Set the attribute bindings
9987
exe->setAttributeBindings(bindings);
10088
// Execute on the provided points individually
@@ -108,7 +96,9 @@ void run(const char* ax, openvdb::GridPtrVec& grids, const AttributeBindings& bi
10896
// @note Throws compiler errors on invalid code. On success, returns
10997
// the executable which can be used multiple times on any inputs
11098
const openvdb::ax::VolumeExecutable::Ptr exe =
111-
compiler.compile<openvdb::ax::VolumeExecutable>(*ast, logger);
99+
compiler.compile<openvdb::ax::VolumeExecutable>(ax);
100+
assert(exe);
101+
112102
//Set the attribute bindings
113103
exe->setAttributeBindings(bindings);
114104
// Execute on the provided volumes

openvdb_ax/openvdb_ax/codegen/ComputeGenerator.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,8 @@ bool ComputeGenerator::generate(const ast::Tree& tree)
138138

139139
// if traverse is false, log should have error, but can error
140140
// without stopping traversal, so check both
141-
142-
const bool result = this->traverse(&tree) && !mLog.hasError();
143-
if (!result) return false;
141+
const size_t err = mLog.errors();
142+
if (!this->traverse(&tree) || (mLog.errors() > err)) return false;
144143

145144
// free strings at terminating blocks
146145

openvdb_ax/openvdb_ax/codegen/PointComputeGenerator.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,8 @@ AttributeRegistry::Ptr PointComputeGenerator::generate(const ast::Tree& tree)
840840
// full code generation
841841
// errors can stop traversal, but dont always, so check the log
842842

843-
if (!this->traverse(&tree) || mLog.hasError()) return nullptr;
843+
const size_t err = mLog.errors();
844+
if (!this->traverse(&tree) || (mLog.errors() > err)) return nullptr;
844845

845846
// insert free calls for any strings
846847

openvdb_ax/openvdb_ax/codegen/VolumeComputeGenerator.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,8 @@ AttributeRegistry::Ptr VolumeComputeGenerator::generate(const ast::Tree& tree)
362362
// full code generation
363363
// errors can stop traversal, but dont always, so check the log
364364

365-
if (!this->traverse(&tree) || mLog.hasError()) return nullptr;
365+
const size_t err = mLog.errors();
366+
if (!this->traverse(&tree) || (mLog.errors() > err)) return nullptr;
366367

367368
// insert free calls for any strings
368369

openvdb_ax/openvdb_ax/compiler/Compiler.cc

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -463,14 +463,16 @@ bool initializeGlobalFunctions(const codegen::FunctionRegistry& registry,
463463
return count == logger.errors();
464464
}
465465

466-
void verifyTypedAccesses(const ast::Tree& tree, openvdb::ax::Logger& logger)
466+
bool verifyTypedAccesses(const ast::Tree& tree, openvdb::ax::Logger& logger)
467467
{
468468
// verify the attributes and external variables requested in the syntax tree
469469
// only have a single type. Note that the executer will also throw a runtime
470470
// error if the same attribute is accessed with different types, but as that's
471471
// currently not a valid state on a PointDataGrid, error in compilation as well
472472
// @todo - introduce a framework for supporting custom preprocessors
473473

474+
const size_t errs = logger.errors();
475+
474476
std::unordered_map<std::string, std::string> nameType;
475477

476478
auto attributeOp =
@@ -504,6 +506,8 @@ void verifyTypedAccesses(const ast::Tree& tree, openvdb::ax::Logger& logger)
504506
};
505507

506508
ast::visitNodeType<ast::ExternalVariable>(tree, externalOp);
509+
510+
return logger.errors() == errs;
507511
}
508512

509513
inline void
@@ -682,6 +686,12 @@ Compiler::compile(const ast::Tree& tree,
682686
CustomData::Ptr data,
683687
Logger& logger)
684688
{
689+
// @todo Not technically necessary for volumes but does the
690+
// executer/bindings handle this?
691+
if (!verifyTypedAccesses(tree, logger)) {
692+
return nullptr;
693+
}
694+
685695
// initialize the module and execution engine - the latter isn't needed
686696
// for IR generation but we leave the creation of the TM to the EE.
687697

@@ -768,8 +778,6 @@ Compiler::compile<PointExecutable>(const ast::Tree& syntaxTree,
768778
PointDefaultModifier modifier;
769779
modifier.traverse(tree.get());
770780

771-
verifyTypedAccesses(*tree, logger);
772-
773781
const std::vector<std::string> functionNames {
774782
codegen::PointKernelBufferRange::getDefaultName(),
775783
codegen::PointKernelAttributeArray::getDefaultName()
@@ -787,8 +795,6 @@ Compiler::compile<VolumeExecutable>(const ast::Tree& syntaxTree,
787795
{
788796
using GenT = codegen::codegen_internal::VolumeComputeGenerator;
789797

790-
verifyTypedAccesses(syntaxTree, logger);
791-
792798
const std::vector<std::string> functionNames {
793799
// codegen::VolumeKernelValue::getDefaultName(), // currently unused directly
794800
codegen::VolumeKernelBuffer::getDefaultName(),

openvdb_ax/openvdb_ax/compiler/Compiler.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,16 @@ class OPENVDB_AX_API Compiler
120120
[&errors] (const std::string& error) {
121121
errors.emplace_back(error + "\n");
122122
},
123-
// ignore warnings
124-
[] (const std::string&) {}
123+
[] (const std::string&) {} // ignore warnings
125124
);
126125
const ast::Tree::ConstPtr syntaxTree = ast::parse(code.c_str(), logger);
127-
typename ExecutableT::Ptr exe;
128-
if (syntaxTree) {
129-
exe = this->compile<ExecutableT>(*syntaxTree, logger, data);
126+
if (!errors.empty()) {
127+
std::ostringstream os;
128+
for (const auto& e : errors) os << e << "\n";
129+
OPENVDB_THROW(AXSyntaxError, os.str());
130130
}
131+
assert(syntaxTree);
132+
typename ExecutableT::Ptr exe = this->compile<ExecutableT>(*syntaxTree, logger, data);
131133
if (!errors.empty()) {
132134
std::ostringstream os;
133135
for (const auto& e : errors) os << e << "\n";
@@ -153,8 +155,7 @@ class OPENVDB_AX_API Compiler
153155
[&errors] (const std::string& error) {
154156
errors.emplace_back(error + "\n");
155157
},
156-
// ignore warnings
157-
[] (const std::string&) {}
158+
[] (const std::string&) {} // ignore warnings
158159
);
159160
auto exe = compile<ExecutableT>(syntaxTree, logger, data);
160161
if (!errors.empty()) {

openvdb_ax/openvdb_ax/compiler/Logger.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ std::string format(const std::string& message,
148148
{
149149
std::stringstream ss;
150150
ss << indent;
151-
if (numbered) ss << "[" << numMessage + 1 << "] ";
151+
if (numbered) ss << "[" << numMessage << "] ";
152152
for (auto c : message) {
153153
ss << c;
154154
if (c == '\n') ss << indent;
@@ -187,19 +187,19 @@ void Logger::setSourceCode(const char* code)
187187
bool Logger::error(const std::string& message,
188188
const Logger::CodeLocation& lineCol)
189189
{
190-
// already exceeded the error limit
191-
if (this->atErrorLimit()) return false;
190+
// check if we've already exceeded the error limit
191+
const bool limit = this->atErrorLimit();
192+
// Always increment the error counter
193+
++mNumErrors;
194+
if (limit) return false;
192195
mErrorOutput(format(this->getErrorPrefix() + message,
193196
lineCol,
194197
this->errors(),
195198
this->getNumberedOutput(),
196199
this->getPrintLines(),
197200
this->mSettings->mIndent,
198201
this->mCode.get()));
199-
++mNumErrors;
200-
// now exceeds the limit
201-
if (this->atErrorLimit()) return false;
202-
else return true;
202+
return !this->atErrorLimit();
203203
}
204204

205205
bool Logger::error(const std::string& message,
@@ -215,14 +215,14 @@ bool Logger::warning(const std::string& message,
215215
return this->error(message + " [warning-as-error]", lineCol);
216216
}
217217
else {
218+
++mNumWarnings;
218219
mWarningOutput(format(this->getWarningPrefix() + message,
219220
lineCol,
220221
this->warnings(),
221222
this->getNumberedOutput(),
222223
this->getPrintLines(),
223224
this->mSettings->mIndent,
224225
this->mCode.get()));
225-
++mNumWarnings;
226226
return true;
227227
}
228228
}

openvdb_ax/openvdb_ax/compiler/Logger.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ namespace ax {
5151
/// parsing, to allow resolution of code locations when they are not
5252
/// explicitly available. The Logger also stores a pointer to the AST Tree
5353
/// that these nodes belong to and the code used to create it.
54+
///
55+
/// @warning The logger is not thread safe. A unique instance of the Logger
56+
/// should be used for unique invocations of ax pipelines.
5457
class OPENVDB_AX_API Logger
5558
{
5659
public:
@@ -75,29 +78,29 @@ class OPENVDB_AX_API Logger
7578
/// associated code location.
7679
/// @param message The error message
7780
/// @param lineCol The line/column number of the offending code
78-
/// @return true if non-fatal and can continue to capture future messages.
81+
/// @return true if can continue to capture future messages.
7982
bool error(const std::string& message, const CodeLocation& lineCol = CodeLocation(0,0));
8083

8184
/// @brief Log a compiler error using the offending AST node. Used in AST
8285
/// traversal.
8386
/// @param message The error message
8487
/// @param node The offending AST node causing the error
85-
/// @return true if non-fatal and can continue to capture future messages.
88+
/// @return true if can continue to capture future messages.
8689
bool error(const std::string& message, const ax::ast::Node* node);
8790

8891
/// @brief Log a compiler warning and its offending code location. If the
8992
/// offending location is (0,0), the message is treated as not having an
9093
/// associated code location.
9194
/// @param message The warning message
9295
/// @param lineCol The line/column number of the offending code
93-
/// @return true if non-fatal and can continue to capture future messages.
96+
/// @return true if can continue to capture future messages.
9497
bool warning(const std::string& message, const CodeLocation& lineCol = CodeLocation(0,0));
9598

9699
/// @brief Log a compiler warning using the offending AST node. Used in AST
97100
/// traversal.
98101
/// @param message The warning message
99102
/// @param node The offending AST node causing the warning
100-
/// @return true if non-fatal and can continue to capture future messages.
103+
/// @return true if can continue to capture future messages.
101104
bool warning(const std::string& message, const ax::ast::Node* node);
102105

103106
///
@@ -130,7 +133,9 @@ class OPENVDB_AX_API Logger
130133
bool getWarningsAsErrors() const;
131134

132135
/// @brief Sets the maximum number of errors that are allowed before
133-
/// compilation should exit
136+
/// compilation should exit.
137+
/// @note The logger will continue to increment the error counter beyond
138+
/// this value but, once reached, it will not invoke the error callback.
134139
/// @param maxErrors The number of allowed errors
135140
void setMaxErrors(const size_t maxErrors = 0);
136141
/// @brief Returns the number of allowed errors
@@ -194,8 +199,8 @@ class OPENVDB_AX_API Logger
194199

195200
friend class ::TestLogger;
196201

197-
std::function<void(const std::string&)> mErrorOutput;
198-
std::function<void(const std::string&)> mWarningOutput;
202+
OutputFunction mErrorOutput;
203+
OutputFunction mWarningOutput;
199204

200205
size_t mNumErrors;
201206
size_t mNumWarnings;

0 commit comments

Comments
 (0)