• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SKSL_DSLPARSER
9 #define SKSL_DSLPARSER
10 
11 #include <memory>
12 #include <unordered_map>
13 #include "include/core/SkStringView.h"
14 #include "include/private/SkSLProgramKind.h"
15 #include "include/private/SkTOptional.h"
16 #include "include/sksl/DSL.h"
17 #include "include/sksl/DSLSymbols.h"
18 #include "src/sksl/SkSLLexer.h"
19 #include "src/sksl/ir/SkSLProgram.h"
20 
21 namespace SkSL {
22 
23 class ErrorReporter;
24 struct Modifiers;
25 struct ParsedModule;
26 class SymbolTable;
27 
28 /**
29  * Consumes .sksl text and invokes DSL functions to instantiate the program.
30  */
31 class DSLParser {
32 public:
33     enum class LayoutToken {
34         LOCATION,
35         OFFSET,
36         BINDING,
37         INDEX,
38         SET,
39         BUILTIN,
40         INPUT_ATTACHMENT_INDEX,
41         ORIGIN_UPPER_LEFT,
42         OVERRIDE_COVERAGE,
43         EARLY_FRAGMENT_TESTS,
44         BLEND_SUPPORT_ALL_EQUATIONS,
45         PUSH_CONSTANT,
46         MARKER,
47         WHEN,
48         KEY,
49         TRACKED,
50         SRGB_UNPREMUL,
51         CTYPE,
52         SKPMCOLOR4F,
53         SKV4,
54         SKRECT,
55         SKIRECT,
56         SKPMCOLOR,
57         SKM44,
58         BOOL,
59         INT,
60         FLOAT,
61     };
62 
63     DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
64               String text);
65 
66     std::unique_ptr<Program> program();
67 
68     SkSL::LoadedModule moduleInheritingFrom(SkSL::ParsedModule baseModule);
69 
70     skstd::string_view text(Token token);
71 
72     PositionInfo position(Token token);
73 
74     PositionInfo position(int line);
75 
76 private:
77     static void InitLayoutMap();
78 
79     /**
80      * Return the next token, including whitespace tokens, from the parse stream.
81      */
82     Token nextRawToken();
83 
84     /**
85      * Return the next non-whitespace token from the parse stream.
86      */
87     Token nextToken();
88 
89     /**
90      * Push a token back onto the parse stream, so that it is the next one read. Only a single level
91      * of pushback is supported (that is, it is an error to call pushback() twice in a row without
92      * an intervening nextToken()).
93      */
94     void pushback(Token t);
95 
96     /**
97      * Returns the next non-whitespace token without consuming it from the stream.
98      */
99     Token peek();
100 
101     /**
102      * Checks to see if the next token is of the specified type. If so, stores it in result (if
103      * result is non-null) and returns true. Otherwise, pushes it back and returns false.
104      */
105     bool checkNext(Token::Kind kind, Token* result = nullptr);
106 
107     /**
108      * Reads the next non-whitespace token and generates an error if it is not the expected type.
109      * The 'expected' string is part of the error message, which reads:
110      *
111      * "expected <expected>, but found '<actual text>'"
112      *
113      * If 'result' is non-null, it is set to point to the token that was read.
114      * Returns true if the read token was as expected, false otherwise.
115      */
116     bool expect(Token::Kind kind, const char* expected, Token* result = nullptr);
117     bool expect(Token::Kind kind, String expected, Token* result = nullptr);
118 
119     /**
120      * Behaves like expect(TK_IDENTIFIER), but also verifies that identifier is not a type.
121      * If the token was actually a type, generates an error message of the form:
122      *
123      * "expected an identifier, but found type 'float2'"
124      */
125     bool expectIdentifier(Token* result);
126 
127     void error(Token token, String msg);
128     void error(int line, String msg);
129 
symbols()130     SymbolTable& symbols() {
131         return *dsl::CurrentSymbolTable();
132     }
133 
134     // these functions parse individual grammar rules from the current parse position; you probably
135     // don't need to call any of these outside of the parser. The function declarations in the .cpp
136     // file have comments describing the grammar rules.
137 
138     void declarations();
139 
140     SKSL_INT arraySize();
141 
142     void directive();
143 
144     bool declaration();
145 
146     bool functionDeclarationEnd(const dsl::DSLModifiers& modifiers,
147                                 dsl::DSLType type,
148                                 const Token& name);
149 
150     struct VarDeclarationsPrefix {
151         PositionInfo fPosition;
152         dsl::DSLModifiers fModifiers;
153         dsl::DSLType fType = dsl::DSLType(dsl::kVoid_Type);
154         Token fName;
155     };
156 
157     bool varDeclarationsPrefix(VarDeclarationsPrefix* prefixData);
158 
159     dsl::DSLStatement varDeclarationsOrExpressionStatement();
160 
161     dsl::DSLStatement varDeclarations();
162 
163     skstd::optional<dsl::DSLType> structDeclaration();
164 
165     SkTArray<dsl::DSLGlobalVar> structVarDeclaration(const dsl::DSLModifiers& modifiers);
166 
167     bool parseArrayDimensions(int line, dsl::DSLType* type);
168 
169     bool parseInitializer(int line, dsl::DSLExpression* initializer);
170 
171     void globalVarDeclarationEnd(PositionInfo position, const dsl::DSLModifiers& mods,
172             dsl::DSLType baseType, skstd::string_view name);
173 
174     dsl::DSLStatement localVarDeclarationEnd(PositionInfo position, const dsl::DSLModifiers& mods,
175             dsl::DSLType baseType, skstd::string_view name);
176 
177     skstd::optional<dsl::DSLWrapper<dsl::DSLParameter>> parameter();
178 
179     int layoutInt();
180 
181     skstd::string_view layoutIdentifier();
182 
183     dsl::DSLLayout layout();
184 
185     dsl::DSLModifiers modifiers();
186 
187     dsl::DSLStatement statement();
188 
189     skstd::optional<dsl::DSLType> type(dsl::DSLModifiers* modifiers);
190 
191     bool interfaceBlock(const dsl::DSLModifiers& mods);
192 
193     dsl::DSLStatement ifStatement();
194 
195     dsl::DSLStatement doStatement();
196 
197     dsl::DSLStatement whileStatement();
198 
199     dsl::DSLStatement forStatement();
200 
201     skstd::optional<dsl::DSLCase> switchCase();
202 
203     dsl::DSLStatement switchStatement();
204 
205     dsl::DSLStatement returnStatement();
206 
207     dsl::DSLStatement breakStatement();
208 
209     dsl::DSLStatement continueStatement();
210 
211     dsl::DSLStatement discardStatement();
212 
213     skstd::optional<dsl::DSLBlock> block();
214 
215     dsl::DSLStatement expressionStatement();
216 
217     dsl::DSLExpression expression();
218 
219     dsl::DSLExpression assignmentExpression();
220 
221     dsl::DSLExpression ternaryExpression();
222 
223     dsl::DSLExpression logicalOrExpression();
224 
225     dsl::DSLExpression logicalXorExpression();
226 
227     dsl::DSLExpression logicalAndExpression();
228 
229     dsl::DSLExpression bitwiseOrExpression();
230 
231     dsl::DSLExpression bitwiseXorExpression();
232 
233     dsl::DSLExpression bitwiseAndExpression();
234 
235     dsl::DSLExpression equalityExpression();
236 
237     dsl::DSLExpression relationalExpression();
238 
239     dsl::DSLExpression shiftExpression();
240 
241     dsl::DSLExpression additiveExpression();
242 
243     dsl::DSLExpression multiplicativeExpression();
244 
245     dsl::DSLExpression unaryExpression();
246 
247     dsl::DSLExpression postfixExpression();
248 
249     dsl::DSLExpression swizzle(int line, dsl::DSLExpression base, skstd::string_view swizzleMask);
250 
251     dsl::DSLExpression call(int line, dsl::DSLExpression base, ExpressionArray args);
252 
253     dsl::DSLExpression suffix(dsl::DSLExpression base);
254 
255     dsl::DSLExpression term();
256 
257     bool intLiteral(SKSL_INT* dest);
258 
259     bool floatLiteral(SKSL_FLOAT* dest);
260 
261     bool boolLiteral(bool* dest);
262 
263     bool identifier(skstd::string_view* dest);
264 
265     class Checkpoint {
266     public:
Checkpoint(DSLParser * p)267         Checkpoint(DSLParser* p) : fParser(p) {
268             fPushbackCheckpoint = fParser->fPushback;
269             fLexerCheckpoint = fParser->fLexer.getCheckpoint();
270             fOldErrorReporter = &dsl::GetErrorReporter();
271             fOldEncounteredFatalError = fParser->fEncounteredFatalError;
272             SkASSERT(fOldErrorReporter);
273             dsl::SetErrorReporter(&fErrorReporter);
274         }
275 
~Checkpoint()276         ~Checkpoint() {
277             SkASSERTF(!fOldErrorReporter,
278                       "Checkpoint was not accepted or rewound before destruction");
279         }
280 
accept()281         void accept() {
282             this->restoreErrorReporter();
283             // Parser errors should have been fatal, but we can encounter other errors like type
284             // mismatches despite accepting the parse. Forward those messages to the actual error
285             // handler now.
286             fErrorReporter.forwardErrors();
287         }
288 
rewind()289         void rewind() {
290             this->restoreErrorReporter();
291             fParser->fPushback = fPushbackCheckpoint;
292             fParser->fLexer.rewindToCheckpoint(fLexerCheckpoint);
293             fParser->fEncounteredFatalError = fOldEncounteredFatalError;
294         }
295 
296     private:
297         class ForwardingErrorReporter : public ErrorReporter {
298         public:
handleError(skstd::string_view msg,PositionInfo pos)299             void handleError(skstd::string_view msg, PositionInfo pos) override {
300                 fErrors.push_back({String(msg), pos});
301             }
302 
forwardErrors()303             void forwardErrors() {
304                 for (Error& error : fErrors) {
305                     dsl::GetErrorReporter().error(error.fMsg.c_str(), error.fPos);
306                 }
307             }
308 
309         private:
310             struct Error {
311                 String fMsg;
312                 PositionInfo fPos;
313             };
314 
315             SkTArray<Error> fErrors;
316         };
317 
restoreErrorReporter()318         void restoreErrorReporter() {
319             SkASSERT(fOldErrorReporter);
320             fErrorReporter.reportPendingErrors(PositionInfo());
321             dsl::SetErrorReporter(fOldErrorReporter);
322             fOldErrorReporter = nullptr;
323         }
324 
325         DSLParser* fParser;
326         Token fPushbackCheckpoint;
327         SkSL::Lexer::Checkpoint fLexerCheckpoint;
328         ForwardingErrorReporter fErrorReporter;
329         ErrorReporter* fOldErrorReporter;
330         bool fOldEncounteredFatalError;
331     };
332 
333     static std::unordered_map<skstd::string_view, LayoutToken>* layoutTokens;
334 
335     Compiler& fCompiler;
336     ProgramSettings fSettings;
337     ErrorReporter* fErrorReporter;
338     bool fEncounteredFatalError;
339     ProgramKind fKind;
340     std::unique_ptr<String> fText;
341     Lexer fLexer;
342     // current parse depth, used to enforce a recursion limit to try to keep us from overflowing the
343     // stack on pathological inputs
344     int fDepth = 0;
345     Token fPushback;
346 
347     friend class AutoDSLDepth;
348     friend class HCodeGenerator;
349 };
350 
351 }  // namespace SkSL
352 
353 #endif
354