blob: d2a8c283e55dc7af59e31e956377ec7035d398c2 [file] [log] [blame]
/*
* 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_DSLPARSER
#define SKSL_DSLPARSER
#include <memory>
#include <unordered_map>
#include "include/core/SkStringView.h"
#include "include/private/SkSLProgramKind.h"
#include "include/private/SkTOptional.h"
#include "include/sksl/DSL.h"
#include "include/sksl/DSLSymbols.h"
#include "src/sksl/SkSLErrorReporter.h"
#include "src/sksl/SkSLLexer.h"
#include "src/sksl/ir/SkSLProgram.h"
#if SKSL_DSL_PARSER
namespace SkSL {
struct Modifiers;
class SymbolTable;
/**
* Consumes .sksl text and invokes DSL functions to instantiate the program.
*/
class DSLParser {
public:
enum class LayoutToken {
LOCATION,
OFFSET,
BINDING,
INDEX,
SET,
BUILTIN,
INPUT_ATTACHMENT_INDEX,
ORIGIN_UPPER_LEFT,
OVERRIDE_COVERAGE,
EARLY_FRAGMENT_TESTS,
BLEND_SUPPORT_ALL_EQUATIONS,
PUSH_CONSTANT,
POINTS,
LINES,
LINE_STRIP,
LINES_ADJACENCY,
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLES_ADJACENCY,
MAX_VERTICES,
INVOCATIONS,
MARKER,
WHEN,
KEY,
TRACKED,
SRGB_UNPREMUL,
CTYPE,
SKPMCOLOR4F,
SKV4,
SKRECT,
SKIRECT,
SKPMCOLOR,
SKM44,
BOOL,
INT,
FLOAT,
};
DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
String text);
std::unique_ptr<Program> program();
skstd::string_view text(Token token);
Position position(Token token);
private:
static void InitLayoutMap();
/**
* Return the next token, including whitespace tokens, from the parse stream.
*/
Token nextRawToken();
/**
* Return the next non-whitespace token from the parse stream.
*/
Token nextToken();
/**
* Push a token back onto the parse stream, so that it is the next one read. Only a single level
* of pushback is supported (that is, it is an error to call pushback() twice in a row without
* an intervening nextToken()).
*/
void pushback(Token t);
/**
* Returns the next non-whitespace token without consuming it from the stream.
*/
Token peek();
/**
* Checks to see if the next token is of the specified type. If so, stores it in result (if
* result is non-null) and returns true. Otherwise, pushes it back and returns false.
*/
bool checkNext(Token::Kind kind, Token* result = nullptr);
/**
* Reads the next non-whitespace token and generates an error if it is not the expected type.
* The 'expected' string is part of the error message, which reads:
*
* "expected <expected>, but found '<actual text>'"
*
* If 'result' is non-null, it is set to point to the token that was read.
* Returns true if the read token was as expected, false otherwise.
*/
bool expect(Token::Kind kind, const char* expected, Token* result = nullptr);
bool expect(Token::Kind kind, String expected, Token* result = nullptr);
/**
* Behaves like expect(TK_IDENTIFIER), but also verifies that identifier is not a type.
* If the token was actually a type, generates an error message of the form:
*
* "expected an identifier, but found type 'float2'"
*/
bool expectIdentifier(Token* result);
ErrorReporter& errors() {
return *fErrorReporter;
}
void error(Token token, String msg);
void error(int offset, String msg);
SymbolTable& symbols() {
return *dsl::CurrentSymbolTable();
}
// these functions parse individual grammar rules from the current parse position; you probably
// don't need to call any of these outside of the parser. The function declarations in the .cpp
// file have comments describing the grammar rules.
ASTNode::ID precision();
bool declaration();
bool functionDeclarationEnd(dsl::DSLModifiers modifiers, dsl::DSLType type, const Token& name);
struct VarDeclarationsPrefix {
dsl::DSLModifiers modifiers;
dsl::DSLType type = dsl::DSLType(dsl::kVoid_Type);
Token name;
};
bool varDeclarationsPrefix(VarDeclarationsPrefix* prefixData);
skstd::optional<dsl::DSLStatement> varDeclarationsOrExpressionStatement();
skstd::optional<dsl::DSLStatement> varDeclarations();
skstd::optional<dsl::DSLType> structDeclaration();
SkTArray<dsl::DSLGlobalVar> structVarDeclaration(dsl::DSLModifiers modifiers);
/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
(LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
template<class T>
SkTArray<T> varDeclarationEnd(dsl::DSLModifiers mods, dsl::DSLType baseType,
skstd::string_view name);
SkTArray<dsl::DSLGlobalVar> globalVarDeclarationEnd(dsl::DSLModifiers modifiers,
dsl::DSLType type, skstd::string_view name);
skstd::optional<dsl::DSLWrapper<dsl::DSLParameter>> parameter();
int layoutInt();
skstd::string_view layoutIdentifier();
dsl::DSLLayout layout();
dsl::DSLModifiers modifiers();
dsl::DSLModifiers modifiersWithDefaults(int defaultFlags);
skstd::optional<dsl::DSLStatement> statement();
skstd::optional<dsl::DSLType> type();
bool interfaceBlock(dsl::DSLModifiers mods);
skstd::optional<dsl::DSLStatement> ifStatement();
skstd::optional<dsl::DSLStatement> doStatement();
skstd::optional<dsl::DSLStatement> whileStatement();
skstd::optional<dsl::DSLStatement> forStatement();
skstd::optional<dsl::DSLCase> switchCase();
skstd::optional<dsl::DSLStatement> switchStatement();
skstd::optional<dsl::DSLStatement> returnStatement();
skstd::optional<dsl::DSLStatement> breakStatement();
skstd::optional<dsl::DSLStatement> continueStatement();
skstd::optional<dsl::DSLStatement> discardStatement();
skstd::optional<dsl::DSLBlock> block();
skstd::optional<dsl::DSLStatement> expressionStatement();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> expression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> assignmentExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> ternaryExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> logicalOrExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> logicalXorExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> logicalAndExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> bitwiseOrExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> bitwiseXorExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> bitwiseAndExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> equalityExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> relationalExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> shiftExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> additiveExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> multiplicativeExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> unaryExpression();
skstd::optional<dsl::DSLWrapper<dsl::DSLExpression>> postfixExpression();
skstd::optional<dsl::Wrapper<dsl::DSLExpression>> swizzle(int offset, dsl::DSLExpression base,
skstd::string_view swizzleMask);
skstd::optional<dsl::Wrapper<dsl::DSLExpression>> call(int offset, dsl::DSLExpression base,
SkTArray<dsl::Wrapper<dsl::DSLExpression>> args);
skstd::optional<dsl::Wrapper<dsl::DSLExpression>> suffix(dsl::DSLExpression base);
skstd::optional<dsl::Wrapper<dsl::DSLExpression>> term();
bool intLiteral(SKSL_INT* dest);
bool floatLiteral(SKSL_FLOAT* dest);
bool boolLiteral(bool* dest);
bool identifier(skstd::string_view* dest);
class Checkpoint : public ErrorReporter {
public:
Checkpoint(DSLParser* p) : fParser(p) {
fPushbackCheckpoint = fParser->fPushback;
fLexerCheckpoint = fParser->fLexer.getCheckpoint();
fErrorReporter = fParser->fErrorReporter;
fParser->fErrorReporter = this;
}
~Checkpoint() override {
SkASSERTF(!fErrorReporter, "Checkpoint was not accepted or rewound before destruction");
}
void accept() {
SkASSERT(fErrorCount == 0 && fErrorReporter);
fParser->fErrorReporter = fErrorReporter;
fErrorReporter = nullptr;
}
void rewind() {
SkASSERT(fErrorReporter);
fParser->fPushback = fPushbackCheckpoint;
fParser->fLexer.rewindToCheckpoint(fLexerCheckpoint);
fParser->fErrorReporter = fErrorReporter;
fErrorReporter = nullptr;
}
void error(int offset, String msg) override {
++fErrorCount;
}
int errorCount() override {
return fErrorCount;
}
void setErrorCount(int numErrors) override {
SkUNREACHABLE;
}
private:
DSLParser* fParser;
Token fPushbackCheckpoint;
int32_t fLexerCheckpoint;
ErrorReporter* fErrorReporter;
int fErrorCount = 0;
};
static std::unordered_map<skstd::string_view, LayoutToken>* layoutTokens;
Compiler& fCompiler;
ProgramSettings fSettings;
ErrorReporter* fErrorReporter;
ProgramKind fKind;
String fText;
Lexer fLexer;
// current parse depth, used to enforce a recursion limit to try to keep us from overflowing the
// stack on pathological inputs
int fDepth = 0;
Token fPushback;
friend class AutoDSLDepth;
friend class HCodeGenerator;
};
} // namespace SkSL
#endif // SKSL_DSL_PARSER
#endif