Add DSL PossibleExpression & PossibleStatement

These are currently unused, but in future CLs they will be used to
capture line number information in DSL error handling.

Change-Id: Ieee730e0ad8323043437972fedb5bec471c367e4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375069
Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
Ethan Nicholas 2021-02-24 15:12:07 -05:00
parent 6165526d45
commit d42932a1b5
9 changed files with 280 additions and 15 deletions

View File

@ -31,16 +31,6 @@ namespace dsl {
// shouldn't pollute the SkSL::dsl namespace with anything else.
using namespace SkSL::SwizzleComponent;
/**
* Class which is notified in the event of an error.
*/
class ErrorHandler {
public:
virtual ~ErrorHandler() {}
virtual void handleError(const char* msg) = 0;
};
/**
* Starts DSL output on the current thread using the specified compiler. This must be called
* prior to any other DSL functions.

View File

@ -0,0 +1,55 @@
/*
* Copyright 2021 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKSL_DSL_ERROR_HANDLING
#define SKSL_DSL_ERROR_HANDLING
namespace SkSL {
namespace dsl {
class PositionInfo {
public:
#if defined(__GNUC__) || defined(__clang__)
PositionInfo(const char* file = __builtin_FILE(), int line = __builtin_LINE())
#else
PositionInfo(const char* file = nullptr, int line = -1)
#endif // defined(__GNUC__) || defined(__clang__)
: fFile(file)
, fLine(line) {}
const char* file_name() {
return fFile;
}
int line() {
return fLine;
}
private:
const char* fFile;
int fLine;
};
/**
* Class which is notified in the event of an error.
*/
class ErrorHandler {
public:
virtual ~ErrorHandler() {}
/**
* Reports a DSL error. Position may not be available, in which case it will be null.
*/
virtual void handleError(const char* msg, PositionInfo* position) = 0;
};
} // namespace dsl
} // namespace SkSL
#endif

View File

@ -66,6 +66,14 @@ DSLExpression::DSLExpression(const DSLVar& var)
var.var(),
SkSL::VariableReference::RefKind::kRead)) {}
DSLExpression::DSLExpression(DSLPossibleExpression expr, PositionInfo pos) {
if (DSLWriter::Compiler().errorCount()) {
DSLWriter::ReportError(DSLWriter::Compiler().errorText(/*showCount=*/false).c_str(), &pos);
DSLWriter::Compiler().setErrorCount(0);
}
fExpression = std::move(expr.fExpression);
}
DSLExpression::~DSLExpression() {
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
if (fExpression && DSLWriter::InFragmentProcessor()) {
@ -189,6 +197,92 @@ std::unique_ptr<SkSL::Expression> DSLExpression::coerceAndRelease(const SkSL::Ty
return DSLWriter::Coerce(this->release(), type).release();
}
DSLPossibleExpression::DSLPossibleExpression(std::unique_ptr<SkSL::Expression> expr)
: fExpression(std::move(expr)) {}
DSLPossibleExpression::~DSLPossibleExpression() {
if (fExpression) {
// this handles incorporating the expression into the output tree
DSLExpression(std::move(fExpression));
}
}
DSLExpression DSLPossibleExpression::x(PositionInfo pos) {
return DSLExpression(this->release()).x();
}
DSLExpression DSLPossibleExpression::y(PositionInfo pos) {
return DSLExpression(this->release()).y();
}
DSLExpression DSLPossibleExpression::z(PositionInfo pos) {
return DSLExpression(this->release()).z();
}
DSLExpression DSLPossibleExpression::w(PositionInfo pos) {
return DSLExpression(this->release()).w();
}
DSLExpression DSLPossibleExpression::r(PositionInfo pos) {
return DSLExpression(this->release()).r();
}
DSLExpression DSLPossibleExpression::g(PositionInfo pos) {
return DSLExpression(this->release()).g();
}
DSLExpression DSLPossibleExpression::b(PositionInfo pos) {
return DSLExpression(this->release()).b();
}
DSLExpression DSLPossibleExpression::a(PositionInfo pos) {
return DSLExpression(this->release()).a();
}
DSLExpression DSLPossibleExpression::field(const char* name, PositionInfo pos) {
return DSLExpression(this->release()).field(name);
}
DSLExpression DSLPossibleExpression::operator=(const DSLVar& var) {
return this->operator=(DSLExpression(var));
}
DSLExpression DSLPossibleExpression::operator=(DSLExpression expr) {
return DSLExpression(this->release()) = std::move(expr);
}
DSLExpression DSLPossibleExpression::operator=(int expr) {
return this->operator=(DSLExpression(expr));
}
DSLExpression DSLPossibleExpression::operator=(float expr) {
return this->operator=(DSLExpression(expr));
}
DSLExpression DSLPossibleExpression::operator[](DSLExpression index) {
return DSLExpression(this->release())[std::move(index)];
}
DSLExpression DSLPossibleExpression::operator++() {
return ++DSLExpression(this->release());
}
DSLExpression DSLPossibleExpression::operator++(int) {
return DSLExpression(this->release())++;
}
DSLExpression DSLPossibleExpression::operator--() {
return --DSLExpression(this->release());
}
DSLExpression DSLPossibleExpression::operator--(int) {
return DSLExpression(this->release())--;
}
std::unique_ptr<SkSL::Expression> DSLPossibleExpression::release() {
return std::move(fExpression);
}
} // namespace dsl
} // namespace SkSL

View File

@ -9,6 +9,7 @@
#define SKSL_DSL_EXPRESSION
#include "include/core/SkTypes.h"
#include "src/sksl/dsl/DSLErrorHandling.h"
#include "src/sksl/ir/SkSLIRNode.h"
#include <cstdint>
@ -20,6 +21,7 @@ class Expression;
namespace dsl {
class DSLPossibleExpression;
class DSLStatement;
class DSLVar;
@ -60,6 +62,8 @@ public:
*/
DSLExpression(const DSLVar& var);
DSLExpression(DSLPossibleExpression expr, PositionInfo pos = PositionInfo());
~DSLExpression();
/**
@ -116,6 +120,7 @@ private:
friend class DSLCore;
friend class DSLFunction;
friend class DSLPossibleExpression;
friend class DSLVar;
friend class DSLWriter;
};
@ -156,6 +161,67 @@ DSLExpression operator++(DSLExpression expr, int);
DSLExpression operator--(DSLExpression expr);
DSLExpression operator--(DSLExpression expr, int);
/**
* Represents an Expression which may have failed and/or have pending errors to report. Converting a
* PossibleExpression into an Expression requires PositionInfo so that any pending errors can be
* reported at the correct position.
*
* PossibleExpression is used instead of Expression in situations where it is not possible to
* capture the PositionInfo at the time of Expression construction (notably in operator overloads,
* where we cannot add default parameters).
*/
class DSLPossibleExpression {
public:
DSLPossibleExpression(std::unique_ptr<SkSL::Expression> expression);
DSLPossibleExpression(DSLPossibleExpression&& other) = default;
~DSLPossibleExpression();
DSLExpression x(PositionInfo pos = PositionInfo());
DSLExpression y(PositionInfo pos = PositionInfo());
DSLExpression z(PositionInfo pos = PositionInfo());
DSLExpression w(PositionInfo pos = PositionInfo());
DSLExpression r(PositionInfo pos = PositionInfo());
DSLExpression g(PositionInfo pos = PositionInfo());
DSLExpression b(PositionInfo pos = PositionInfo());
DSLExpression a(PositionInfo pos = PositionInfo());
DSLExpression field(const char* name, PositionInfo pos = PositionInfo());
DSLExpression operator=(const DSLVar& var);
DSLExpression operator=(DSLExpression expr);
DSLExpression operator=(int expr);
DSLExpression operator=(float expr);
DSLExpression operator[](DSLExpression index);
DSLExpression operator++();
DSLExpression operator++(int);
DSLExpression operator--();
DSLExpression operator--(int);
std::unique_ptr<SkSL::Expression> release();
private:
std::unique_ptr<SkSL::Expression> fExpression;
friend class DSLExpression;
};
} // namespace dsl
} // namespace SkSL

View File

@ -42,6 +42,17 @@ DSLStatement::DSLStatement(std::unique_ptr<SkSL::Statement> stmt)
}
}
DSLStatement::DSLStatement(DSLPossibleExpression expr, PositionInfo pos)
: DSLStatement(DSLExpression(std::move(expr), pos)) {}
DSLStatement::DSLStatement(DSLPossibleStatement stmt, PositionInfo pos) {
if (DSLWriter::Compiler().errorCount()) {
DSLWriter::ReportError(DSLWriter::Compiler().errorText(/*showCount=*/false).c_str(), &pos);
DSLWriter::Compiler().setErrorCount(0);
}
fStatement = std::move(stmt.fStatement);
}
DSLStatement::~DSLStatement() {
#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
if (fStatement && DSLWriter::InFragmentProcessor()) {
@ -52,6 +63,16 @@ DSLStatement::~DSLStatement() {
SkASSERTF(!fStatement, "Statement destroyed without being incorporated into program");
}
DSLPossibleStatement::DSLPossibleStatement(std::unique_ptr<SkSL::Statement> statement)
: fStatement(std::move(statement)) {}
DSLPossibleStatement::~DSLPossibleStatement() {
if (fStatement) {
// this handles incorporating the expression into the output tree
DSLStatement(std::move(fStatement));
}
}
} // namespace dsl
} // namespace SkSL

View File

@ -10,6 +10,7 @@
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "src/sksl/dsl/DSLErrorHandling.h"
#include <memory>
@ -24,6 +25,8 @@ namespace dsl {
class DSLBlock;
class DSLExpression;
class DSLPossibleExpression;
class DSLPossibleStatement;
class DSLVar;
class DSLStatement {
@ -32,6 +35,10 @@ public:
DSLStatement(DSLExpression expr);
DSLStatement(DSLPossibleExpression expr, PositionInfo pos = PositionInfo());
DSLStatement(DSLPossibleStatement stmt, PositionInfo pos = PositionInfo());
DSLStatement(DSLBlock block);
DSLStatement(DSLStatement&&) = default;
@ -52,9 +59,36 @@ private:
friend class DSLBlock;
friend class DSLCore;
friend class DSLExpression;
friend class DSLPossibleStatement;
friend class DSLWriter;
};
/**
* Represents a Statement which may have failed and/or have pending errors to report. Converting a
* PossibleStatement into a Statement requires PositionInfo so that any pending errors can be
* reported at the correct position.
*
* PossibleStatement is used instead of Statement in situations where it is not possible to capture
* the PositionInfo at the time of Statement construction.
*/
class DSLPossibleStatement {
public:
DSLPossibleStatement(std::unique_ptr<SkSL::Statement> stmt);
DSLPossibleStatement(DSLPossibleStatement&& other) = default;
~DSLPossibleStatement();
std::unique_ptr<SkSL::Statement> release() {
return std::move(fStatement);
}
private:
std::unique_ptr<SkSL::Statement> fStatement;
friend class DSLStatement;
};
} // namespace dsl
} // namespace SkSL

View File

@ -141,10 +141,15 @@ DSLStatement DSLWriter::ConvertSwitch(std::unique_ptr<Expression> value,
IRGenerator().fSymbolTable);
}
void DSLWriter::ReportError(const char* msg) {
void DSLWriter::ReportError(const char* msg, PositionInfo* info) {
if (info && !info->file_name()) {
info = nullptr;
}
if (Instance().fErrorHandler) {
Instance().fErrorHandler->handleError(msg);
Instance().fErrorHandler->handleError(msg, info);
} else if (info) {
SK_ABORT("%s: %d: %sNo SkSL DSL error handler configured, treating this as a fatal error\n",
info->file_name(), info->line(), msg);
} else {
SK_ABORT("%sNo SkSL DSL error handler configured, treating this as a fatal error\n", msg);
}

View File

@ -167,7 +167,7 @@ public:
* Notifies the current ErrorHandler that a DSL error has occurred. With a null ErrorHandler
* (the default), any errors will be dumped to stderr and a fatal exception will be generated.
*/
static void ReportError(const char* msg);
static void ReportError(const char* msg, PositionInfo* info = nullptr);
/**
* Returns whether name mangling is enabled. This should always be enabled outside of tests.

View File

@ -44,7 +44,7 @@ public:
SetErrorHandler(nullptr);
}
void handleError(const char* msg) override {
void handleError(const char* msg, PositionInfo* pos) override {
REPORTER_ASSERT(fReporter, !strcmp(msg, fMsg),
"Error mismatch: expected:\n%sbut received:\n%s", fMsg, msg);
fMsg = nullptr;