| /* |
| * 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 |