xref: /third_party/skia/src/sksl/SkSLDSLParser.cpp (revision cb93a386)
1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/sksl/SkSLDSLParser.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/private/SkSLString.h"
11cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h"
12cb93a386Sopenharmony_ci#include "src/sksl/SkSLConstantFolder.h"
13cb93a386Sopenharmony_ci#include "src/sksl/SkSLThreadContext.h"
14cb93a386Sopenharmony_ci#include "src/sksl/dsl/priv/DSLWriter.h"
15cb93a386Sopenharmony_ci#include "src/sksl/dsl/priv/DSL_priv.h"
16cb93a386Sopenharmony_ci#include <memory>
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ciusing namespace SkSL::dsl;
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_cinamespace SkSL {
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_cistatic constexpr int kMaxParseDepth = 50;
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic int parse_modifier_token(Token::Kind token) {
25cb93a386Sopenharmony_ci    switch (token) {
26cb93a386Sopenharmony_ci        case Token::Kind::TK_UNIFORM:        return Modifiers::kUniform_Flag;
27cb93a386Sopenharmony_ci        case Token::Kind::TK_CONST:          return Modifiers::kConst_Flag;
28cb93a386Sopenharmony_ci        case Token::Kind::TK_IN:             return Modifiers::kIn_Flag;
29cb93a386Sopenharmony_ci        case Token::Kind::TK_OUT:            return Modifiers::kOut_Flag;
30cb93a386Sopenharmony_ci        case Token::Kind::TK_INOUT:          return Modifiers::kIn_Flag | Modifiers::kOut_Flag;
31cb93a386Sopenharmony_ci        case Token::Kind::TK_FLAT:           return Modifiers::kFlat_Flag;
32cb93a386Sopenharmony_ci        case Token::Kind::TK_NOPERSPECTIVE:  return Modifiers::kNoPerspective_Flag;
33cb93a386Sopenharmony_ci        case Token::Kind::TK_HASSIDEEFFECTS: return Modifiers::kHasSideEffects_Flag;
34cb93a386Sopenharmony_ci        case Token::Kind::TK_INLINE:         return Modifiers::kInline_Flag;
35cb93a386Sopenharmony_ci        case Token::Kind::TK_NOINLINE:       return Modifiers::kNoInline_Flag;
36cb93a386Sopenharmony_ci        case Token::Kind::TK_HIGHP:          return Modifiers::kHighp_Flag;
37cb93a386Sopenharmony_ci        case Token::Kind::TK_MEDIUMP:        return Modifiers::kMediump_Flag;
38cb93a386Sopenharmony_ci        case Token::Kind::TK_LOWP:           return Modifiers::kLowp_Flag;
39cb93a386Sopenharmony_ci        case Token::Kind::TK_ES3:            return Modifiers::kES3_Flag;
40cb93a386Sopenharmony_ci        default:                             return 0;
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci}
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ciclass AutoDSLDepth {
45cb93a386Sopenharmony_cipublic:
46cb93a386Sopenharmony_ci    AutoDSLDepth(DSLParser* p)
47cb93a386Sopenharmony_ci    : fParser(p)
48cb93a386Sopenharmony_ci    , fDepth(0) {}
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_ci    ~AutoDSLDepth() {
51cb93a386Sopenharmony_ci        fParser->fDepth -= fDepth;
52cb93a386Sopenharmony_ci    }
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci    bool increase() {
55cb93a386Sopenharmony_ci        ++fDepth;
56cb93a386Sopenharmony_ci        ++fParser->fDepth;
57cb93a386Sopenharmony_ci        if (fParser->fDepth > kMaxParseDepth) {
58cb93a386Sopenharmony_ci            fParser->error(fParser->peek(), String("exceeded max parse depth"));
59cb93a386Sopenharmony_ci            return false;
60cb93a386Sopenharmony_ci        }
61cb93a386Sopenharmony_ci        return true;
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciprivate:
65cb93a386Sopenharmony_ci    DSLParser* fParser;
66cb93a386Sopenharmony_ci    int fDepth;
67cb93a386Sopenharmony_ci};
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ciclass AutoDSLSymbolTable {
70cb93a386Sopenharmony_cipublic:
71cb93a386Sopenharmony_ci    AutoDSLSymbolTable() {
72cb93a386Sopenharmony_ci        dsl::PushSymbolTable();
73cb93a386Sopenharmony_ci    }
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci    ~AutoDSLSymbolTable() {
76cb93a386Sopenharmony_ci        dsl::PopSymbolTable();
77cb93a386Sopenharmony_ci    }
78cb93a386Sopenharmony_ci};
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_cistd::unordered_map<skstd::string_view, DSLParser::LayoutToken>* DSLParser::layoutTokens;
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_civoid DSLParser::InitLayoutMap() {
83cb93a386Sopenharmony_ci    layoutTokens = new std::unordered_map<skstd::string_view, LayoutToken>;
84cb93a386Sopenharmony_ci    #define TOKEN(name, text) (*layoutTokens)[text] = LayoutToken::name
85cb93a386Sopenharmony_ci    TOKEN(LOCATION,                     "location");
86cb93a386Sopenharmony_ci    TOKEN(OFFSET,                       "offset");
87cb93a386Sopenharmony_ci    TOKEN(BINDING,                      "binding");
88cb93a386Sopenharmony_ci    TOKEN(INDEX,                        "index");
89cb93a386Sopenharmony_ci    TOKEN(SET,                          "set");
90cb93a386Sopenharmony_ci    TOKEN(BUILTIN,                      "builtin");
91cb93a386Sopenharmony_ci    TOKEN(INPUT_ATTACHMENT_INDEX,       "input_attachment_index");
92cb93a386Sopenharmony_ci    TOKEN(ORIGIN_UPPER_LEFT,            "origin_upper_left");
93cb93a386Sopenharmony_ci    TOKEN(BLEND_SUPPORT_ALL_EQUATIONS,  "blend_support_all_equations");
94cb93a386Sopenharmony_ci    TOKEN(PUSH_CONSTANT,                "push_constant");
95cb93a386Sopenharmony_ci    TOKEN(SRGB_UNPREMUL,                "srgb_unpremul");
96cb93a386Sopenharmony_ci    #undef TOKEN
97cb93a386Sopenharmony_ci}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ciDSLParser::DSLParser(Compiler* compiler, const ProgramSettings& settings, ProgramKind kind,
100cb93a386Sopenharmony_ci                     String text)
101cb93a386Sopenharmony_ci    : fCompiler(*compiler)
102cb93a386Sopenharmony_ci    , fSettings(settings)
103cb93a386Sopenharmony_ci    , fKind(kind)
104cb93a386Sopenharmony_ci    , fText(std::make_unique<String>(std::move(text)))
105cb93a386Sopenharmony_ci    , fPushback(Token::Kind::TK_NONE, /*offset=*/-1, /*length=*/-1, /*line=*/-1) {
106cb93a386Sopenharmony_ci    // We don't want to have to worry about manually releasing all of the objects in the event that
107cb93a386Sopenharmony_ci    // an error occurs
108cb93a386Sopenharmony_ci    fSettings.fAssertDSLObjectsReleased = false;
109cb93a386Sopenharmony_ci    // We manage our symbol tables manually, so no need for name mangling
110cb93a386Sopenharmony_ci    fSettings.fDSLMangling = false;
111cb93a386Sopenharmony_ci    fLexer.start(*fText);
112cb93a386Sopenharmony_ci    static const bool layoutMapInitialized = []{ InitLayoutMap(); return true; }();
113cb93a386Sopenharmony_ci    (void) layoutMapInitialized;
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ciToken DSLParser::nextRawToken() {
117cb93a386Sopenharmony_ci    if (fPushback.fKind != Token::Kind::TK_NONE) {
118cb93a386Sopenharmony_ci        Token result = fPushback;
119cb93a386Sopenharmony_ci        fPushback.fKind = Token::Kind::TK_NONE;
120cb93a386Sopenharmony_ci        return result;
121cb93a386Sopenharmony_ci    }
122cb93a386Sopenharmony_ci    return fLexer.next();
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ciToken DSLParser::nextToken() {
126cb93a386Sopenharmony_ci    for (;;) {
127cb93a386Sopenharmony_ci        Token token = this->nextRawToken();
128cb93a386Sopenharmony_ci        switch (token.fKind) {
129cb93a386Sopenharmony_ci            case Token::Kind::TK_WHITESPACE:
130cb93a386Sopenharmony_ci            case Token::Kind::TK_LINE_COMMENT:
131cb93a386Sopenharmony_ci            case Token::Kind::TK_BLOCK_COMMENT:
132cb93a386Sopenharmony_ci                continue;
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci            case Token::Kind::TK_RESERVED:
135cb93a386Sopenharmony_ci                this->error(token, "'" + this->text(token) + "' is a reserved word");
136cb93a386Sopenharmony_ci                token.fKind = Token::Kind::TK_IDENTIFIER;
137cb93a386Sopenharmony_ci                [[fallthrough]];
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci            default:
140cb93a386Sopenharmony_ci                return token;
141cb93a386Sopenharmony_ci        }
142cb93a386Sopenharmony_ci    }
143cb93a386Sopenharmony_ci}
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_civoid DSLParser::pushback(Token t) {
146cb93a386Sopenharmony_ci    SkASSERT(fPushback.fKind == Token::Kind::TK_NONE);
147cb93a386Sopenharmony_ci    fPushback = std::move(t);
148cb93a386Sopenharmony_ci}
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ciToken DSLParser::peek() {
151cb93a386Sopenharmony_ci    if (fPushback.fKind == Token::Kind::TK_NONE) {
152cb93a386Sopenharmony_ci        fPushback = this->nextToken();
153cb93a386Sopenharmony_ci    }
154cb93a386Sopenharmony_ci    return fPushback;
155cb93a386Sopenharmony_ci}
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_cibool DSLParser::checkNext(Token::Kind kind, Token* result) {
158cb93a386Sopenharmony_ci    if (fPushback.fKind != Token::Kind::TK_NONE && fPushback.fKind != kind) {
159cb93a386Sopenharmony_ci        return false;
160cb93a386Sopenharmony_ci    }
161cb93a386Sopenharmony_ci    Token next = this->nextToken();
162cb93a386Sopenharmony_ci    if (next.fKind == kind) {
163cb93a386Sopenharmony_ci        if (result) {
164cb93a386Sopenharmony_ci            *result = next;
165cb93a386Sopenharmony_ci        }
166cb93a386Sopenharmony_ci        return true;
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci    this->pushback(std::move(next));
169cb93a386Sopenharmony_ci    return false;
170cb93a386Sopenharmony_ci}
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_cibool DSLParser::expect(Token::Kind kind, const char* expected, Token* result) {
173cb93a386Sopenharmony_ci    Token next = this->nextToken();
174cb93a386Sopenharmony_ci    if (next.fKind == kind) {
175cb93a386Sopenharmony_ci        if (result) {
176cb93a386Sopenharmony_ci            *result = std::move(next);
177cb93a386Sopenharmony_ci        }
178cb93a386Sopenharmony_ci        return true;
179cb93a386Sopenharmony_ci    } else {
180cb93a386Sopenharmony_ci        this->error(next, "expected " + String(expected) + ", but found '" +
181cb93a386Sopenharmony_ci                    this->text(next) + "'");
182cb93a386Sopenharmony_ci        this->fEncounteredFatalError = true;
183cb93a386Sopenharmony_ci        return false;
184cb93a386Sopenharmony_ci    }
185cb93a386Sopenharmony_ci}
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_cibool DSLParser::expectIdentifier(Token* result) {
188cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", result)) {
189cb93a386Sopenharmony_ci        return false;
190cb93a386Sopenharmony_ci    }
191cb93a386Sopenharmony_ci    if (IsBuiltinType(this->text(*result))) {
192cb93a386Sopenharmony_ci        this->error(*result, "expected an identifier, but found type '" +
193cb93a386Sopenharmony_ci                             this->text(*result) + "'");
194cb93a386Sopenharmony_ci        this->fEncounteredFatalError = true;
195cb93a386Sopenharmony_ci        return false;
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci    return true;
198cb93a386Sopenharmony_ci}
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ciskstd::string_view DSLParser::text(Token token) {
201cb93a386Sopenharmony_ci    return skstd::string_view(fText->data() + token.fOffset, token.fLength);
202cb93a386Sopenharmony_ci}
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ciPositionInfo DSLParser::position(Token t) {
205cb93a386Sopenharmony_ci    return this->position(t.fLine);
206cb93a386Sopenharmony_ci}
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ciPositionInfo DSLParser::position(int line) {
209cb93a386Sopenharmony_ci    return PositionInfo("<unknown>", line);
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_civoid DSLParser::error(Token token, String msg) {
213cb93a386Sopenharmony_ci    this->error(token.fLine, msg);
214cb93a386Sopenharmony_ci}
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_civoid DSLParser::error(int line, String msg) {
217cb93a386Sopenharmony_ci    GetErrorReporter().error(msg.c_str(), this->position(line));
218cb93a386Sopenharmony_ci}
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci/* declaration* END_OF_FILE */
221cb93a386Sopenharmony_cistd::unique_ptr<Program> DSLParser::program() {
222cb93a386Sopenharmony_ci    ErrorReporter* errorReporter = &fCompiler.errorReporter();
223cb93a386Sopenharmony_ci    Start(&fCompiler, fKind, fSettings);
224cb93a386Sopenharmony_ci    SetErrorReporter(errorReporter);
225cb93a386Sopenharmony_ci    errorReporter->setSource(fText->c_str());
226cb93a386Sopenharmony_ci    this->declarations();
227cb93a386Sopenharmony_ci    std::unique_ptr<Program> result;
228cb93a386Sopenharmony_ci    if (!GetErrorReporter().errorCount()) {
229cb93a386Sopenharmony_ci        result = dsl::ReleaseProgram(std::move(fText));
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci    errorReporter->setSource(nullptr);
232cb93a386Sopenharmony_ci    End();
233cb93a386Sopenharmony_ci    return result;
234cb93a386Sopenharmony_ci}
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ciSkSL::LoadedModule DSLParser::moduleInheritingFrom(SkSL::ParsedModule baseModule) {
237cb93a386Sopenharmony_ci    ErrorReporter* errorReporter = &fCompiler.errorReporter();
238cb93a386Sopenharmony_ci    StartModule(&fCompiler, fKind, fSettings, std::move(baseModule));
239cb93a386Sopenharmony_ci    SetErrorReporter(errorReporter);
240cb93a386Sopenharmony_ci    errorReporter->setSource(fText->c_str());
241cb93a386Sopenharmony_ci    this->declarations();
242cb93a386Sopenharmony_ci    CurrentSymbolTable()->takeOwnershipOfString(std::move(*fText));
243cb93a386Sopenharmony_ci    SkSL::LoadedModule result{ fKind, CurrentSymbolTable(),
244cb93a386Sopenharmony_ci            std::move(ThreadContext::ProgramElements()) };
245cb93a386Sopenharmony_ci    errorReporter->setSource(nullptr);
246cb93a386Sopenharmony_ci    End();
247cb93a386Sopenharmony_ci    return result;
248cb93a386Sopenharmony_ci}
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_civoid DSLParser::declarations() {
251cb93a386Sopenharmony_ci    fEncounteredFatalError = false;
252cb93a386Sopenharmony_ci    bool done = false;
253cb93a386Sopenharmony_ci    while (!done) {
254cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
255cb93a386Sopenharmony_ci            case Token::Kind::TK_END_OF_FILE:
256cb93a386Sopenharmony_ci                done = true;
257cb93a386Sopenharmony_ci                break;
258cb93a386Sopenharmony_ci            case Token::Kind::TK_DIRECTIVE:
259cb93a386Sopenharmony_ci                this->directive();
260cb93a386Sopenharmony_ci                break;
261cb93a386Sopenharmony_ci            case Token::Kind::TK_INVALID: {
262cb93a386Sopenharmony_ci                this->nextToken();
263cb93a386Sopenharmony_ci                this->error(this->peek(), String("invalid token"));
264cb93a386Sopenharmony_ci                done = true;
265cb93a386Sopenharmony_ci                break;
266cb93a386Sopenharmony_ci            }
267cb93a386Sopenharmony_ci            default:
268cb93a386Sopenharmony_ci                this->declaration();
269cb93a386Sopenharmony_ci                done = fEncounteredFatalError;
270cb93a386Sopenharmony_ci                break;
271cb93a386Sopenharmony_ci        }
272cb93a386Sopenharmony_ci    }
273cb93a386Sopenharmony_ci}
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci/* DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
276cb93a386Sopenharmony_civoid DSLParser::directive() {
277cb93a386Sopenharmony_ci    Token start;
278cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_DIRECTIVE, "a directive", &start)) {
279cb93a386Sopenharmony_ci        return;
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci    skstd::string_view text = this->text(start);
282cb93a386Sopenharmony_ci    if (text == "#extension") {
283cb93a386Sopenharmony_ci        Token name;
284cb93a386Sopenharmony_ci        if (!this->expectIdentifier(&name)) {
285cb93a386Sopenharmony_ci            return;
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_COLON, "':'")) {
288cb93a386Sopenharmony_ci            return;
289cb93a386Sopenharmony_ci        }
290cb93a386Sopenharmony_ci        Token behavior;
291cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &behavior)) {
292cb93a386Sopenharmony_ci            return;
293cb93a386Sopenharmony_ci        }
294cb93a386Sopenharmony_ci        skstd::string_view behaviorText = this->text(behavior);
295cb93a386Sopenharmony_ci        if (behaviorText == "disable") {
296cb93a386Sopenharmony_ci            return;
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci        if (behaviorText != "require" && behaviorText != "enable" && behaviorText != "warn") {
299cb93a386Sopenharmony_ci            this->error(behavior, "expected 'require', 'enable', 'warn', or 'disable'");
300cb93a386Sopenharmony_ci        }
301cb93a386Sopenharmony_ci        // We don't currently do anything different between require, enable, and warn
302cb93a386Sopenharmony_ci        dsl::AddExtension(this->text(name));
303cb93a386Sopenharmony_ci    } else {
304cb93a386Sopenharmony_ci        this->error(start, "unsupported directive '" + this->text(start) + "'");
305cb93a386Sopenharmony_ci    }
306cb93a386Sopenharmony_ci}
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter (COMMA parameter)* RPAREN
309cb93a386Sopenharmony_ci   (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
310cb93a386Sopenharmony_cibool DSLParser::declaration() {
311cb93a386Sopenharmony_ci    Token lookahead = this->peek();
312cb93a386Sopenharmony_ci    switch (lookahead.fKind) {
313cb93a386Sopenharmony_ci        case Token::Kind::TK_SEMICOLON:
314cb93a386Sopenharmony_ci            this->nextToken();
315cb93a386Sopenharmony_ci            this->error(lookahead, "expected a declaration, but found ';'");
316cb93a386Sopenharmony_ci            return false;
317cb93a386Sopenharmony_ci        default:
318cb93a386Sopenharmony_ci            break;
319cb93a386Sopenharmony_ci    }
320cb93a386Sopenharmony_ci    DSLModifiers modifiers = this->modifiers();
321cb93a386Sopenharmony_ci    lookahead = this->peek();
322cb93a386Sopenharmony_ci    if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && !IsType(this->text(lookahead))) {
323cb93a386Sopenharmony_ci        // we have an identifier that's not a type, could be the start of an interface block
324cb93a386Sopenharmony_ci        return this->interfaceBlock(modifiers);
325cb93a386Sopenharmony_ci    }
326cb93a386Sopenharmony_ci    if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
327cb93a386Sopenharmony_ci        this->nextToken();
328cb93a386Sopenharmony_ci        Declare(modifiers, position(lookahead));
329cb93a386Sopenharmony_ci        return true;
330cb93a386Sopenharmony_ci    }
331cb93a386Sopenharmony_ci    if (lookahead.fKind == Token::Kind::TK_STRUCT) {
332cb93a386Sopenharmony_ci        this->structVarDeclaration(modifiers);
333cb93a386Sopenharmony_ci        return true;
334cb93a386Sopenharmony_ci    }
335cb93a386Sopenharmony_ci    skstd::optional<DSLType> type = this->type(&modifiers);
336cb93a386Sopenharmony_ci    if (!type) {
337cb93a386Sopenharmony_ci        return false;
338cb93a386Sopenharmony_ci    }
339cb93a386Sopenharmony_ci    Token name;
340cb93a386Sopenharmony_ci    if (!this->expectIdentifier(&name)) {
341cb93a386Sopenharmony_ci        return false;
342cb93a386Sopenharmony_ci    }
343cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_LPAREN)) {
344cb93a386Sopenharmony_ci        return this->functionDeclarationEnd(modifiers, *type, name);
345cb93a386Sopenharmony_ci    } else {
346cb93a386Sopenharmony_ci        this->globalVarDeclarationEnd(this->position(name), modifiers, *type, this->text(name));
347cb93a386Sopenharmony_ci        return true;
348cb93a386Sopenharmony_ci    }
349cb93a386Sopenharmony_ci}
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci/* (RPAREN | VOID RPAREN | parameter (COMMA parameter)* RPAREN) (block | SEMICOLON) */
352cb93a386Sopenharmony_cibool DSLParser::functionDeclarationEnd(const DSLModifiers& modifiers,
353cb93a386Sopenharmony_ci                                       DSLType type,
354cb93a386Sopenharmony_ci                                       const Token& name) {
355cb93a386Sopenharmony_ci    SkTArray<DSLWrapper<DSLParameter>> parameters;
356cb93a386Sopenharmony_ci    Token lookahead = this->peek();
357cb93a386Sopenharmony_ci    if (lookahead.fKind == Token::Kind::TK_RPAREN) {
358cb93a386Sopenharmony_ci        // `()` means no parameters at all.
359cb93a386Sopenharmony_ci    } else if (lookahead.fKind == Token::Kind::TK_IDENTIFIER && this->text(lookahead) == "void") {
360cb93a386Sopenharmony_ci        // `(void)` also means no parameters at all.
361cb93a386Sopenharmony_ci        this->nextToken();
362cb93a386Sopenharmony_ci    } else {
363cb93a386Sopenharmony_ci        for (;;) {
364cb93a386Sopenharmony_ci            skstd::optional<DSLWrapper<DSLParameter>> parameter = this->parameter();
365cb93a386Sopenharmony_ci            if (!parameter) {
366cb93a386Sopenharmony_ci                return false;
367cb93a386Sopenharmony_ci            }
368cb93a386Sopenharmony_ci            parameters.push_back(std::move(*parameter));
369cb93a386Sopenharmony_ci            if (!this->checkNext(Token::Kind::TK_COMMA)) {
370cb93a386Sopenharmony_ci                break;
371cb93a386Sopenharmony_ci            }
372cb93a386Sopenharmony_ci        }
373cb93a386Sopenharmony_ci    }
374cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
375cb93a386Sopenharmony_ci        return false;
376cb93a386Sopenharmony_ci    }
377cb93a386Sopenharmony_ci    SkTArray<DSLParameter*> parameterPointers;
378cb93a386Sopenharmony_ci    for (DSLWrapper<DSLParameter>& param : parameters) {
379cb93a386Sopenharmony_ci        parameterPointers.push_back(&param.get());
380cb93a386Sopenharmony_ci    }
381cb93a386Sopenharmony_ci    DSLFunction result(modifiers, type, this->text(name), parameterPointers, this->position(name));
382cb93a386Sopenharmony_ci    if (!this->checkNext(Token::Kind::TK_SEMICOLON)) {
383cb93a386Sopenharmony_ci        AutoDSLSymbolTable symbols;
384cb93a386Sopenharmony_ci        for (DSLParameter* var : parameterPointers) {
385cb93a386Sopenharmony_ci            AddToSymbolTable(*var);
386cb93a386Sopenharmony_ci        }
387cb93a386Sopenharmony_ci        skstd::optional<DSLBlock> body = this->block();
388cb93a386Sopenharmony_ci        if (!body) {
389cb93a386Sopenharmony_ci            return false;
390cb93a386Sopenharmony_ci        }
391cb93a386Sopenharmony_ci        result.define(std::move(*body), this->position(name));
392cb93a386Sopenharmony_ci    }
393cb93a386Sopenharmony_ci    return true;
394cb93a386Sopenharmony_ci}
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_ciSKSL_INT DSLParser::arraySize() {
397cb93a386Sopenharmony_ci    DSLExpression sizeExpr = this->expression();
398cb93a386Sopenharmony_ci    if (!sizeExpr.isValid()) {
399cb93a386Sopenharmony_ci        return 1;
400cb93a386Sopenharmony_ci    }
401cb93a386Sopenharmony_ci    std::unique_ptr<SkSL::Expression> sizeLiteral = sizeExpr.release();
402cb93a386Sopenharmony_ci    SKSL_INT size;
403cb93a386Sopenharmony_ci    if (!ConstantFolder::GetConstantInt(*sizeLiteral, &size)) {
404cb93a386Sopenharmony_ci        this->error(sizeLiteral->fLine, "array size must be an integer");
405cb93a386Sopenharmony_ci        return 1;
406cb93a386Sopenharmony_ci    }
407cb93a386Sopenharmony_ci    if (size > INT32_MAX) {
408cb93a386Sopenharmony_ci        this->error(sizeLiteral->fLine, "array size out of bounds");
409cb93a386Sopenharmony_ci        return 1;
410cb93a386Sopenharmony_ci    }
411cb93a386Sopenharmony_ci    if (size <= 0) {
412cb93a386Sopenharmony_ci        this->error(sizeLiteral->fLine, "array size must be positive");
413cb93a386Sopenharmony_ci        return 1;
414cb93a386Sopenharmony_ci    }
415cb93a386Sopenharmony_ci    return size;
416cb93a386Sopenharmony_ci}
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_cibool DSLParser::parseArrayDimensions(int line, DSLType* type) {
419cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_LBRACKET)) {
420cb93a386Sopenharmony_ci        if (this->checkNext(Token::Kind::TK_RBRACKET)) {
421cb93a386Sopenharmony_ci            this->error(line, "expected array dimension");
422cb93a386Sopenharmony_ci        } else {
423cb93a386Sopenharmony_ci            *type = Array(*type, this->arraySize(), this->position(line));
424cb93a386Sopenharmony_ci            if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
425cb93a386Sopenharmony_ci                return false;
426cb93a386Sopenharmony_ci            }
427cb93a386Sopenharmony_ci        }
428cb93a386Sopenharmony_ci    }
429cb93a386Sopenharmony_ci    return true;
430cb93a386Sopenharmony_ci}
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_cibool DSLParser::parseInitializer(int line, DSLExpression* initializer) {
433cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_EQ)) {
434cb93a386Sopenharmony_ci        DSLExpression value = this->assignmentExpression();
435cb93a386Sopenharmony_ci        if (!value.hasValue()) {
436cb93a386Sopenharmony_ci            return false;
437cb93a386Sopenharmony_ci        }
438cb93a386Sopenharmony_ci        initializer->swap(value);
439cb93a386Sopenharmony_ci    }
440cb93a386Sopenharmony_ci    return true;
441cb93a386Sopenharmony_ci}
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ci/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
444cb93a386Sopenharmony_ci   (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
445cb93a386Sopenharmony_civoid DSLParser::globalVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
446cb93a386Sopenharmony_ci        dsl::DSLType baseType, skstd::string_view name) {
447cb93a386Sopenharmony_ci    using namespace dsl;
448cb93a386Sopenharmony_ci    int line = this->peek().fLine;
449cb93a386Sopenharmony_ci    DSLType type = baseType;
450cb93a386Sopenharmony_ci    DSLExpression initializer;
451cb93a386Sopenharmony_ci    if (!this->parseArrayDimensions(line, &type)) {
452cb93a386Sopenharmony_ci        return;
453cb93a386Sopenharmony_ci    }
454cb93a386Sopenharmony_ci    if (!this->parseInitializer(line, &initializer)) {
455cb93a386Sopenharmony_ci        return;
456cb93a386Sopenharmony_ci    }
457cb93a386Sopenharmony_ci    DSLGlobalVar first(mods, type, name, std::move(initializer), pos);
458cb93a386Sopenharmony_ci    Declare(first);
459cb93a386Sopenharmony_ci    AddToSymbolTable(first);
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_COMMA)) {
462cb93a386Sopenharmony_ci        type = baseType;
463cb93a386Sopenharmony_ci        Token identifierName;
464cb93a386Sopenharmony_ci        if (!this->expectIdentifier(&identifierName)) {
465cb93a386Sopenharmony_ci            return;
466cb93a386Sopenharmony_ci        }
467cb93a386Sopenharmony_ci        if (!this->parseArrayDimensions(line, &type)) {
468cb93a386Sopenharmony_ci            return;
469cb93a386Sopenharmony_ci        }
470cb93a386Sopenharmony_ci        DSLExpression anotherInitializer;
471cb93a386Sopenharmony_ci        if (!this->parseInitializer(line, &anotherInitializer)) {
472cb93a386Sopenharmony_ci            return;
473cb93a386Sopenharmony_ci        }
474cb93a386Sopenharmony_ci        DSLGlobalVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
475cb93a386Sopenharmony_ci                this->position(line));
476cb93a386Sopenharmony_ci        Declare(next);
477cb93a386Sopenharmony_ci        AddToSymbolTable(next, this->position(identifierName));
478cb93a386Sopenharmony_ci    }
479cb93a386Sopenharmony_ci    this->expect(Token::Kind::TK_SEMICOLON, "';'");
480cb93a386Sopenharmony_ci}
481cb93a386Sopenharmony_ci
482cb93a386Sopenharmony_ci/* (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)? (COMMA IDENTIFER
483cb93a386Sopenharmony_ci   (LBRACKET expression? RBRACKET)* (EQ assignmentExpression)?)* SEMICOLON */
484cb93a386Sopenharmony_ciDSLStatement DSLParser::localVarDeclarationEnd(PositionInfo pos, const dsl::DSLModifiers& mods,
485cb93a386Sopenharmony_ci        dsl::DSLType baseType, skstd::string_view name) {
486cb93a386Sopenharmony_ci    using namespace dsl;
487cb93a386Sopenharmony_ci    int line = this->peek().fLine;
488cb93a386Sopenharmony_ci    DSLType type = baseType;
489cb93a386Sopenharmony_ci    DSLExpression initializer;
490cb93a386Sopenharmony_ci    if (!this->parseArrayDimensions(line, &type)) {
491cb93a386Sopenharmony_ci        return {};
492cb93a386Sopenharmony_ci    }
493cb93a386Sopenharmony_ci    if (!this->parseInitializer(line, &initializer)) {
494cb93a386Sopenharmony_ci        return {};
495cb93a386Sopenharmony_ci    }
496cb93a386Sopenharmony_ci    DSLVar first(mods, type, name, std::move(initializer), pos);
497cb93a386Sopenharmony_ci    DSLStatement result = Declare(first);
498cb93a386Sopenharmony_ci    AddToSymbolTable(first);
499cb93a386Sopenharmony_ci
500cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_COMMA)) {
501cb93a386Sopenharmony_ci        type = baseType;
502cb93a386Sopenharmony_ci        Token identifierName;
503cb93a386Sopenharmony_ci        if (!this->expectIdentifier(&identifierName)) {
504cb93a386Sopenharmony_ci            return result;
505cb93a386Sopenharmony_ci        }
506cb93a386Sopenharmony_ci        if (!this->parseArrayDimensions(line, &type)) {
507cb93a386Sopenharmony_ci            return result;
508cb93a386Sopenharmony_ci        }
509cb93a386Sopenharmony_ci        DSLExpression anotherInitializer;
510cb93a386Sopenharmony_ci        if (!this->parseInitializer(line, &anotherInitializer)) {
511cb93a386Sopenharmony_ci            return result;
512cb93a386Sopenharmony_ci        }
513cb93a386Sopenharmony_ci        DSLVar next(mods, type, this->text(identifierName), std::move(anotherInitializer),
514cb93a386Sopenharmony_ci                this->position(line));
515cb93a386Sopenharmony_ci        DSLWriter::AddVarDeclaration(result, next);
516cb93a386Sopenharmony_ci        AddToSymbolTable(next, this->position(identifierName));
517cb93a386Sopenharmony_ci    }
518cb93a386Sopenharmony_ci    this->expect(Token::Kind::TK_SEMICOLON, "';'");
519cb93a386Sopenharmony_ci    return result;
520cb93a386Sopenharmony_ci}
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_ci/* (varDeclarations | expressionStatement) */
523cb93a386Sopenharmony_ciDSLStatement DSLParser::varDeclarationsOrExpressionStatement() {
524cb93a386Sopenharmony_ci    Token nextToken = this->peek();
525cb93a386Sopenharmony_ci    if (nextToken.fKind == Token::Kind::TK_CONST) {
526cb93a386Sopenharmony_ci        // Statements that begin with `const` might be variable declarations, but can't be legal
527cb93a386Sopenharmony_ci        // SkSL expression-statements. (SkSL constructors don't take a `const` modifier.)
528cb93a386Sopenharmony_ci        return this->varDeclarations();
529cb93a386Sopenharmony_ci    }
530cb93a386Sopenharmony_ci
531cb93a386Sopenharmony_ci    if (nextToken.fKind == Token::Kind::TK_HIGHP ||
532cb93a386Sopenharmony_ci        nextToken.fKind == Token::Kind::TK_MEDIUMP ||
533cb93a386Sopenharmony_ci        nextToken.fKind == Token::Kind::TK_LOWP ||
534cb93a386Sopenharmony_ci        IsType(this->text(nextToken))) {
535cb93a386Sopenharmony_ci        // Statements that begin with a typename are most often variable declarations, but
536cb93a386Sopenharmony_ci        // occasionally the type is part of a constructor, and these are actually expression-
537cb93a386Sopenharmony_ci        // statements in disguise. First, attempt the common case: parse it as a vardecl.
538cb93a386Sopenharmony_ci        Checkpoint checkpoint(this);
539cb93a386Sopenharmony_ci        VarDeclarationsPrefix prefix;
540cb93a386Sopenharmony_ci        if (this->varDeclarationsPrefix(&prefix)) {
541cb93a386Sopenharmony_ci            checkpoint.accept();
542cb93a386Sopenharmony_ci            return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
543cb93a386Sopenharmony_ci                                                this->text(prefix.fName));
544cb93a386Sopenharmony_ci        }
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_ci        // If this statement wasn't actually a vardecl after all, rewind and try parsing it as an
547cb93a386Sopenharmony_ci        // expression-statement instead.
548cb93a386Sopenharmony_ci        checkpoint.rewind();
549cb93a386Sopenharmony_ci    }
550cb93a386Sopenharmony_ci    return this->expressionStatement();
551cb93a386Sopenharmony_ci}
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ci// Helper function for varDeclarations(). If this function succeeds, we assume that the rest of the
554cb93a386Sopenharmony_ci// statement is a variable-declaration statement, not an expression-statement.
555cb93a386Sopenharmony_cibool DSLParser::varDeclarationsPrefix(VarDeclarationsPrefix* prefixData) {
556cb93a386Sopenharmony_ci    prefixData->fPosition = this->position(this->peek());
557cb93a386Sopenharmony_ci    prefixData->fModifiers = this->modifiers();
558cb93a386Sopenharmony_ci    skstd::optional<DSLType> type = this->type(&prefixData->fModifiers);
559cb93a386Sopenharmony_ci    if (!type) {
560cb93a386Sopenharmony_ci        return false;
561cb93a386Sopenharmony_ci    }
562cb93a386Sopenharmony_ci    prefixData->fType = *type;
563cb93a386Sopenharmony_ci    return this->expectIdentifier(&prefixData->fName);
564cb93a386Sopenharmony_ci}
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ci/* modifiers type IDENTIFIER varDeclarationEnd */
567cb93a386Sopenharmony_ciDSLStatement DSLParser::varDeclarations() {
568cb93a386Sopenharmony_ci    VarDeclarationsPrefix prefix;
569cb93a386Sopenharmony_ci    if (!this->varDeclarationsPrefix(&prefix)) {
570cb93a386Sopenharmony_ci        return {};
571cb93a386Sopenharmony_ci    }
572cb93a386Sopenharmony_ci    return this->localVarDeclarationEnd(prefix.fPosition, prefix.fModifiers, prefix.fType,
573cb93a386Sopenharmony_ci            this->text(prefix.fName));
574cb93a386Sopenharmony_ci}
575cb93a386Sopenharmony_ci
576cb93a386Sopenharmony_ci/* STRUCT IDENTIFIER LBRACE varDeclaration* RBRACE */
577cb93a386Sopenharmony_ciskstd::optional<DSLType> DSLParser::structDeclaration() {
578cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
579cb93a386Sopenharmony_ci    if (!depth.increase()) {
580cb93a386Sopenharmony_ci        return skstd::nullopt;
581cb93a386Sopenharmony_ci    }
582cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_STRUCT, "'struct'")) {
583cb93a386Sopenharmony_ci        return skstd::nullopt;
584cb93a386Sopenharmony_ci    }
585cb93a386Sopenharmony_ci    Token name;
586cb93a386Sopenharmony_ci    if (!this->expectIdentifier(&name)) {
587cb93a386Sopenharmony_ci        return skstd::nullopt;
588cb93a386Sopenharmony_ci    }
589cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
590cb93a386Sopenharmony_ci        return skstd::nullopt;
591cb93a386Sopenharmony_ci    }
592cb93a386Sopenharmony_ci    SkTArray<DSLField> fields;
593cb93a386Sopenharmony_ci    while (!this->checkNext(Token::Kind::TK_RBRACE)) {
594cb93a386Sopenharmony_ci        DSLModifiers modifiers = this->modifiers();
595cb93a386Sopenharmony_ci        skstd::optional<DSLType> type = this->type(&modifiers);
596cb93a386Sopenharmony_ci        if (!type) {
597cb93a386Sopenharmony_ci            return skstd::nullopt;
598cb93a386Sopenharmony_ci        }
599cb93a386Sopenharmony_ci
600cb93a386Sopenharmony_ci        do {
601cb93a386Sopenharmony_ci            DSLType actualType = *type;
602cb93a386Sopenharmony_ci            Token memberName;
603cb93a386Sopenharmony_ci            if (!this->expectIdentifier(&memberName)) {
604cb93a386Sopenharmony_ci                return skstd::nullopt;
605cb93a386Sopenharmony_ci            }
606cb93a386Sopenharmony_ci
607cb93a386Sopenharmony_ci            while (this->checkNext(Token::Kind::TK_LBRACKET)) {
608cb93a386Sopenharmony_ci                actualType = dsl::Array(actualType, this->arraySize(), this->position(memberName));
609cb93a386Sopenharmony_ci                if (!this->expect(Token::Kind::TK_RBRACKET, "']'")) {
610cb93a386Sopenharmony_ci                    return skstd::nullopt;
611cb93a386Sopenharmony_ci                }
612cb93a386Sopenharmony_ci            }
613cb93a386Sopenharmony_ci            fields.push_back(DSLField(modifiers, std::move(actualType), this->text(memberName),
614cb93a386Sopenharmony_ci                    this->position(memberName)));
615cb93a386Sopenharmony_ci        } while (this->checkNext(Token::Kind::TK_COMMA));
616cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
617cb93a386Sopenharmony_ci            return skstd::nullopt;
618cb93a386Sopenharmony_ci        }
619cb93a386Sopenharmony_ci    }
620cb93a386Sopenharmony_ci    if (fields.empty()) {
621cb93a386Sopenharmony_ci        this->error(name, "struct '" + this->text(name) + "' must contain at least one field");
622cb93a386Sopenharmony_ci    }
623cb93a386Sopenharmony_ci    return dsl::Struct(this->text(name), SkMakeSpan(fields), this->position(name));
624cb93a386Sopenharmony_ci}
625cb93a386Sopenharmony_ci
626cb93a386Sopenharmony_ci/* structDeclaration ((IDENTIFIER varDeclarationEnd) | SEMICOLON) */
627cb93a386Sopenharmony_ciSkTArray<dsl::DSLGlobalVar> DSLParser::structVarDeclaration(const DSLModifiers& modifiers) {
628cb93a386Sopenharmony_ci    skstd::optional<DSLType> type = this->structDeclaration();
629cb93a386Sopenharmony_ci    if (!type) {
630cb93a386Sopenharmony_ci        return {};
631cb93a386Sopenharmony_ci    }
632cb93a386Sopenharmony_ci    Token name;
633cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_IDENTIFIER, &name)) {
634cb93a386Sopenharmony_ci        this->globalVarDeclarationEnd(this->position(name), modifiers, std::move(*type),
635cb93a386Sopenharmony_ci                this->text(name));
636cb93a386Sopenharmony_ci    } else {
637cb93a386Sopenharmony_ci        this->expect(Token::Kind::TK_SEMICOLON, "';'");
638cb93a386Sopenharmony_ci    }
639cb93a386Sopenharmony_ci    return {};
640cb93a386Sopenharmony_ci}
641cb93a386Sopenharmony_ci
642cb93a386Sopenharmony_ci/* modifiers type IDENTIFIER (LBRACKET INT_LITERAL RBRACKET)? */
643cb93a386Sopenharmony_ciskstd::optional<DSLWrapper<DSLParameter>> DSLParser::parameter() {
644cb93a386Sopenharmony_ci    DSLModifiers modifiers = this->modifiers();
645cb93a386Sopenharmony_ci    skstd::optional<DSLType> type = this->type(&modifiers);
646cb93a386Sopenharmony_ci    if (!type) {
647cb93a386Sopenharmony_ci        return skstd::nullopt;
648cb93a386Sopenharmony_ci    }
649cb93a386Sopenharmony_ci    Token name;
650cb93a386Sopenharmony_ci    if (!this->expectIdentifier(&name)) {
651cb93a386Sopenharmony_ci        return skstd::nullopt;
652cb93a386Sopenharmony_ci    }
653cb93a386Sopenharmony_ci    if (!this->parseArrayDimensions(name.fLine, &type.value())) {
654cb93a386Sopenharmony_ci        return skstd::nullopt;
655cb93a386Sopenharmony_ci    }
656cb93a386Sopenharmony_ci    return {{DSLParameter(modifiers, *type, this->text(name), this->position(name))}};
657cb93a386Sopenharmony_ci}
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci/** EQ INT_LITERAL */
660cb93a386Sopenharmony_ciint DSLParser::layoutInt() {
661cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_EQ, "'='")) {
662cb93a386Sopenharmony_ci        return -1;
663cb93a386Sopenharmony_ci    }
664cb93a386Sopenharmony_ci    Token resultToken;
665cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_INT_LITERAL, "a non-negative integer", &resultToken)) {
666cb93a386Sopenharmony_ci        return -1;
667cb93a386Sopenharmony_ci    }
668cb93a386Sopenharmony_ci    skstd::string_view resultFrag = this->text(resultToken);
669cb93a386Sopenharmony_ci    SKSL_INT resultValue;
670cb93a386Sopenharmony_ci    if (!SkSL::stoi(resultFrag, &resultValue)) {
671cb93a386Sopenharmony_ci        this->error(resultToken, "value in layout is too large: " + resultFrag);
672cb93a386Sopenharmony_ci        return -1;
673cb93a386Sopenharmony_ci    }
674cb93a386Sopenharmony_ci    return resultValue;
675cb93a386Sopenharmony_ci}
676cb93a386Sopenharmony_ci
677cb93a386Sopenharmony_ci/** EQ IDENTIFIER */
678cb93a386Sopenharmony_ciskstd::string_view DSLParser::layoutIdentifier() {
679cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_EQ, "'='")) {
680cb93a386Sopenharmony_ci        return {};
681cb93a386Sopenharmony_ci    }
682cb93a386Sopenharmony_ci    Token resultToken;
683cb93a386Sopenharmony_ci    if (!this->expectIdentifier(&resultToken)) {
684cb93a386Sopenharmony_ci        return {};
685cb93a386Sopenharmony_ci    }
686cb93a386Sopenharmony_ci    return this->text(resultToken);
687cb93a386Sopenharmony_ci}
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
690cb93a386Sopenharmony_ciDSLLayout DSLParser::layout() {
691cb93a386Sopenharmony_ci    DSLLayout result;
692cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_LAYOUT)) {
693cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
694cb93a386Sopenharmony_ci            return result;
695cb93a386Sopenharmony_ci        }
696cb93a386Sopenharmony_ci        for (;;) {
697cb93a386Sopenharmony_ci            Token t = this->nextToken();
698cb93a386Sopenharmony_ci            String text(this->text(t));
699cb93a386Sopenharmony_ci            auto found = layoutTokens->find(text);
700cb93a386Sopenharmony_ci            if (found != layoutTokens->end()) {
701cb93a386Sopenharmony_ci                switch (found->second) {
702cb93a386Sopenharmony_ci                    case LayoutToken::ORIGIN_UPPER_LEFT:
703cb93a386Sopenharmony_ci                        result.originUpperLeft(this->position(t));
704cb93a386Sopenharmony_ci                        break;
705cb93a386Sopenharmony_ci                    case LayoutToken::PUSH_CONSTANT:
706cb93a386Sopenharmony_ci                        result.pushConstant(this->position(t));
707cb93a386Sopenharmony_ci                        break;
708cb93a386Sopenharmony_ci                    case LayoutToken::BLEND_SUPPORT_ALL_EQUATIONS:
709cb93a386Sopenharmony_ci                        result.blendSupportAllEquations(this->position(t));
710cb93a386Sopenharmony_ci                        break;
711cb93a386Sopenharmony_ci                    case LayoutToken::SRGB_UNPREMUL:
712cb93a386Sopenharmony_ci                        result.srgbUnpremul(this->position(t));
713cb93a386Sopenharmony_ci                        break;
714cb93a386Sopenharmony_ci                    case LayoutToken::LOCATION:
715cb93a386Sopenharmony_ci                        result.location(this->layoutInt(), this->position(t));
716cb93a386Sopenharmony_ci                        break;
717cb93a386Sopenharmony_ci                    case LayoutToken::OFFSET:
718cb93a386Sopenharmony_ci                        result.offset(this->layoutInt(), this->position(t));
719cb93a386Sopenharmony_ci                        break;
720cb93a386Sopenharmony_ci                    case LayoutToken::BINDING:
721cb93a386Sopenharmony_ci                        result.binding(this->layoutInt(), this->position(t));
722cb93a386Sopenharmony_ci                        break;
723cb93a386Sopenharmony_ci                    case LayoutToken::INDEX:
724cb93a386Sopenharmony_ci                        result.index(this->layoutInt(), this->position(t));
725cb93a386Sopenharmony_ci                        break;
726cb93a386Sopenharmony_ci                    case LayoutToken::SET:
727cb93a386Sopenharmony_ci                        result.set(this->layoutInt(), this->position(t));
728cb93a386Sopenharmony_ci                        break;
729cb93a386Sopenharmony_ci                    case LayoutToken::BUILTIN:
730cb93a386Sopenharmony_ci                        result.builtin(this->layoutInt(), this->position(t));
731cb93a386Sopenharmony_ci                        break;
732cb93a386Sopenharmony_ci                    case LayoutToken::INPUT_ATTACHMENT_INDEX:
733cb93a386Sopenharmony_ci                        result.inputAttachmentIndex(this->layoutInt(), this->position(t));
734cb93a386Sopenharmony_ci                        break;
735cb93a386Sopenharmony_ci                    default:
736cb93a386Sopenharmony_ci                        this->error(t, "'" + text + "' is not a valid layout qualifier");
737cb93a386Sopenharmony_ci                        break;
738cb93a386Sopenharmony_ci                }
739cb93a386Sopenharmony_ci            } else {
740cb93a386Sopenharmony_ci                this->error(t, "'" + text + "' is not a valid layout qualifier");
741cb93a386Sopenharmony_ci            }
742cb93a386Sopenharmony_ci            if (this->checkNext(Token::Kind::TK_RPAREN)) {
743cb93a386Sopenharmony_ci                break;
744cb93a386Sopenharmony_ci            }
745cb93a386Sopenharmony_ci            if (!this->expect(Token::Kind::TK_COMMA, "','")) {
746cb93a386Sopenharmony_ci                break;
747cb93a386Sopenharmony_ci            }
748cb93a386Sopenharmony_ci        }
749cb93a386Sopenharmony_ci    }
750cb93a386Sopenharmony_ci    return result;
751cb93a386Sopenharmony_ci}
752cb93a386Sopenharmony_ci
753cb93a386Sopenharmony_ci/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
754cb93a386Sopenharmony_ci            VARYING | INLINE)* */
755cb93a386Sopenharmony_ciDSLModifiers DSLParser::modifiers() {
756cb93a386Sopenharmony_ci    DSLLayout layout = this->layout();
757cb93a386Sopenharmony_ci    int flags = 0;
758cb93a386Sopenharmony_ci    for (;;) {
759cb93a386Sopenharmony_ci        // TODO(ethannicholas): handle duplicate / incompatible flags
760cb93a386Sopenharmony_ci        int tokenFlag = parse_modifier_token(peek().fKind);
761cb93a386Sopenharmony_ci        if (!tokenFlag) {
762cb93a386Sopenharmony_ci            break;
763cb93a386Sopenharmony_ci        }
764cb93a386Sopenharmony_ci        flags |= tokenFlag;
765cb93a386Sopenharmony_ci        this->nextToken();
766cb93a386Sopenharmony_ci    }
767cb93a386Sopenharmony_ci    return DSLModifiers(std::move(layout), flags);
768cb93a386Sopenharmony_ci}
769cb93a386Sopenharmony_ci
770cb93a386Sopenharmony_ci/* ifStatement | forStatement | doStatement | whileStatement | block | expression */
771cb93a386Sopenharmony_ciDSLStatement DSLParser::statement() {
772cb93a386Sopenharmony_ci    Token start = this->nextToken();
773cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
774cb93a386Sopenharmony_ci    if (!depth.increase()) {
775cb93a386Sopenharmony_ci        return {};
776cb93a386Sopenharmony_ci    }
777cb93a386Sopenharmony_ci    this->pushback(start);
778cb93a386Sopenharmony_ci    switch (start.fKind) {
779cb93a386Sopenharmony_ci        case Token::Kind::TK_IF: // fall through
780cb93a386Sopenharmony_ci        case Token::Kind::TK_STATIC_IF:
781cb93a386Sopenharmony_ci            return this->ifStatement();
782cb93a386Sopenharmony_ci        case Token::Kind::TK_FOR:
783cb93a386Sopenharmony_ci            return this->forStatement();
784cb93a386Sopenharmony_ci        case Token::Kind::TK_DO:
785cb93a386Sopenharmony_ci            return this->doStatement();
786cb93a386Sopenharmony_ci        case Token::Kind::TK_WHILE:
787cb93a386Sopenharmony_ci            return this->whileStatement();
788cb93a386Sopenharmony_ci        case Token::Kind::TK_SWITCH: // fall through
789cb93a386Sopenharmony_ci        case Token::Kind::TK_STATIC_SWITCH:
790cb93a386Sopenharmony_ci            return this->switchStatement();
791cb93a386Sopenharmony_ci        case Token::Kind::TK_RETURN:
792cb93a386Sopenharmony_ci            return this->returnStatement();
793cb93a386Sopenharmony_ci        case Token::Kind::TK_BREAK:
794cb93a386Sopenharmony_ci            return this->breakStatement();
795cb93a386Sopenharmony_ci        case Token::Kind::TK_CONTINUE:
796cb93a386Sopenharmony_ci            return this->continueStatement();
797cb93a386Sopenharmony_ci        case Token::Kind::TK_DISCARD:
798cb93a386Sopenharmony_ci            return this->discardStatement();
799cb93a386Sopenharmony_ci        case Token::Kind::TK_LBRACE: {
800cb93a386Sopenharmony_ci            skstd::optional<DSLBlock> result = this->block();
801cb93a386Sopenharmony_ci            return result ? DSLStatement(std::move(*result)) : DSLStatement();
802cb93a386Sopenharmony_ci        }
803cb93a386Sopenharmony_ci        case Token::Kind::TK_SEMICOLON:
804cb93a386Sopenharmony_ci            this->nextToken();
805cb93a386Sopenharmony_ci            return dsl::Block();
806cb93a386Sopenharmony_ci        case Token::Kind::TK_HIGHP:
807cb93a386Sopenharmony_ci        case Token::Kind::TK_MEDIUMP:
808cb93a386Sopenharmony_ci        case Token::Kind::TK_LOWP:
809cb93a386Sopenharmony_ci        case Token::Kind::TK_CONST:
810cb93a386Sopenharmony_ci        case Token::Kind::TK_IDENTIFIER:
811cb93a386Sopenharmony_ci            return this->varDeclarationsOrExpressionStatement();
812cb93a386Sopenharmony_ci        default:
813cb93a386Sopenharmony_ci            return this->expressionStatement();
814cb93a386Sopenharmony_ci    }
815cb93a386Sopenharmony_ci}
816cb93a386Sopenharmony_ci
817cb93a386Sopenharmony_ci/* IDENTIFIER(type) (LBRACKET intLiteral? RBRACKET)* QUESTION? */
818cb93a386Sopenharmony_ciskstd::optional<DSLType> DSLParser::type(DSLModifiers* modifiers) {
819cb93a386Sopenharmony_ci    Token type;
820cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_IDENTIFIER, "a type", &type)) {
821cb93a386Sopenharmony_ci        return skstd::nullopt;
822cb93a386Sopenharmony_ci    }
823cb93a386Sopenharmony_ci    if (!IsType(this->text(type))) {
824cb93a386Sopenharmony_ci        this->error(type, ("no type named '" + this->text(type) + "'").c_str());
825cb93a386Sopenharmony_ci        return skstd::nullopt;
826cb93a386Sopenharmony_ci    }
827cb93a386Sopenharmony_ci    DSLType result(this->text(type), modifiers, this->position(type));
828cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_LBRACKET)) {
829cb93a386Sopenharmony_ci        if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
830cb93a386Sopenharmony_ci            result = Array(result, this->arraySize(), this->position(type));
831cb93a386Sopenharmony_ci        } else {
832cb93a386Sopenharmony_ci            this->error(this->peek(), "expected array dimension");
833cb93a386Sopenharmony_ci        }
834cb93a386Sopenharmony_ci        this->expect(Token::Kind::TK_RBRACKET, "']'");
835cb93a386Sopenharmony_ci    }
836cb93a386Sopenharmony_ci    return result;
837cb93a386Sopenharmony_ci}
838cb93a386Sopenharmony_ci
839cb93a386Sopenharmony_ci/* IDENTIFIER LBRACE
840cb93a386Sopenharmony_ci     varDeclaration+
841cb93a386Sopenharmony_ci   RBRACE (IDENTIFIER (LBRACKET expression? RBRACKET)*)? SEMICOLON */
842cb93a386Sopenharmony_cibool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
843cb93a386Sopenharmony_ci    Token typeName;
844cb93a386Sopenharmony_ci    if (!this->expectIdentifier(&typeName)) {
845cb93a386Sopenharmony_ci        return false;
846cb93a386Sopenharmony_ci    }
847cb93a386Sopenharmony_ci    if (peek().fKind != Token::Kind::TK_LBRACE) {
848cb93a386Sopenharmony_ci        // we only get into interfaceBlock if we found a top-level identifier which was not a type.
849cb93a386Sopenharmony_ci        // 99% of the time, the user was not actually intending to create an interface block, so
850cb93a386Sopenharmony_ci        // it's better to report it as an unknown type
851cb93a386Sopenharmony_ci        this->error(typeName, "no type named '" + this->text(typeName) + "'");
852cb93a386Sopenharmony_ci        return false;
853cb93a386Sopenharmony_ci    }
854cb93a386Sopenharmony_ci    this->nextToken();
855cb93a386Sopenharmony_ci    SkTArray<dsl::Field> fields;
856cb93a386Sopenharmony_ci    while (!this->checkNext(Token::Kind::TK_RBRACE)) {
857cb93a386Sopenharmony_ci        DSLModifiers fieldModifiers = this->modifiers();
858cb93a386Sopenharmony_ci        skstd::optional<dsl::DSLType> type = this->type(&fieldModifiers);
859cb93a386Sopenharmony_ci        if (!type) {
860cb93a386Sopenharmony_ci            return false;
861cb93a386Sopenharmony_ci        }
862cb93a386Sopenharmony_ci        do {
863cb93a386Sopenharmony_ci            Token fieldName;
864cb93a386Sopenharmony_ci            if (!this->expect(Token::Kind::TK_IDENTIFIER, "an identifier", &fieldName)) {
865cb93a386Sopenharmony_ci                return false;
866cb93a386Sopenharmony_ci            }
867cb93a386Sopenharmony_ci            DSLType actualType = *type;
868cb93a386Sopenharmony_ci            if (this->checkNext(Token::Kind::TK_LBRACKET)) {
869cb93a386Sopenharmony_ci                Token sizeToken = this->peek();
870cb93a386Sopenharmony_ci                if (sizeToken.fKind != Token::Kind::TK_RBRACKET) {
871cb93a386Sopenharmony_ci                    actualType = Array(std::move(actualType), this->arraySize(),
872cb93a386Sopenharmony_ci                                       this->position(typeName));
873cb93a386Sopenharmony_ci                } else {
874cb93a386Sopenharmony_ci                    this->error(sizeToken, "unsized arrays are not permitted");
875cb93a386Sopenharmony_ci                }
876cb93a386Sopenharmony_ci                this->expect(Token::Kind::TK_RBRACKET, "']'");
877cb93a386Sopenharmony_ci            }
878cb93a386Sopenharmony_ci            if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
879cb93a386Sopenharmony_ci                return false;
880cb93a386Sopenharmony_ci            }
881cb93a386Sopenharmony_ci            fields.push_back(dsl::Field(fieldModifiers, std::move(actualType),
882cb93a386Sopenharmony_ci                    this->text(fieldName), this->position(fieldName)));
883cb93a386Sopenharmony_ci        }
884cb93a386Sopenharmony_ci        while (this->checkNext(Token::Kind::TK_COMMA));
885cb93a386Sopenharmony_ci    }
886cb93a386Sopenharmony_ci    skstd::string_view instanceName;
887cb93a386Sopenharmony_ci    Token instanceNameToken;
888cb93a386Sopenharmony_ci    SKSL_INT arraySize = 0;
889cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_IDENTIFIER, &instanceNameToken)) {
890cb93a386Sopenharmony_ci        instanceName = this->text(instanceNameToken);
891cb93a386Sopenharmony_ci        if (this->checkNext(Token::Kind::TK_LBRACKET)) {
892cb93a386Sopenharmony_ci            arraySize = this->arraySize();
893cb93a386Sopenharmony_ci            this->expect(Token::Kind::TK_RBRACKET, "']'");
894cb93a386Sopenharmony_ci        }
895cb93a386Sopenharmony_ci    }
896cb93a386Sopenharmony_ci    this->expect(Token::Kind::TK_SEMICOLON, "';'");
897cb93a386Sopenharmony_ci    if (fields.empty()) {
898cb93a386Sopenharmony_ci        this->error(typeName, "interface block '" + this->text(typeName) +
899cb93a386Sopenharmony_ci                              "' must contain at least one member");
900cb93a386Sopenharmony_ci    } else {
901cb93a386Sopenharmony_ci        dsl::InterfaceBlock(modifiers, this->text(typeName), std::move(fields), instanceName,
902cb93a386Sopenharmony_ci                            arraySize, this->position(typeName));
903cb93a386Sopenharmony_ci    }
904cb93a386Sopenharmony_ci    return true;
905cb93a386Sopenharmony_ci}
906cb93a386Sopenharmony_ci
907cb93a386Sopenharmony_ci/* IF LPAREN expression RPAREN statement (ELSE statement)? */
908cb93a386Sopenharmony_ciDSLStatement DSLParser::ifStatement() {
909cb93a386Sopenharmony_ci    Token start;
910cb93a386Sopenharmony_ci    bool isStatic = this->checkNext(Token::Kind::TK_STATIC_IF, &start);
911cb93a386Sopenharmony_ci    if (!isStatic && !this->expect(Token::Kind::TK_IF, "'if'", &start)) {
912cb93a386Sopenharmony_ci        return {};
913cb93a386Sopenharmony_ci    }
914cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
915cb93a386Sopenharmony_ci        return {};
916cb93a386Sopenharmony_ci    }
917cb93a386Sopenharmony_ci    DSLExpression test = this->expression();
918cb93a386Sopenharmony_ci    if (!test.hasValue()) {
919cb93a386Sopenharmony_ci        return {};
920cb93a386Sopenharmony_ci    }
921cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
922cb93a386Sopenharmony_ci        return {};
923cb93a386Sopenharmony_ci    }
924cb93a386Sopenharmony_ci    DSLStatement ifTrue = this->statement();
925cb93a386Sopenharmony_ci    if (!ifTrue.hasValue()) {
926cb93a386Sopenharmony_ci        return {};
927cb93a386Sopenharmony_ci    }
928cb93a386Sopenharmony_ci    DSLStatement ifFalse;
929cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_ELSE)) {
930cb93a386Sopenharmony_ci        ifFalse = this->statement();
931cb93a386Sopenharmony_ci        if (!ifFalse.hasValue()) {
932cb93a386Sopenharmony_ci            return {};
933cb93a386Sopenharmony_ci        }
934cb93a386Sopenharmony_ci    }
935cb93a386Sopenharmony_ci    if (isStatic) {
936cb93a386Sopenharmony_ci        return StaticIf(std::move(test), std::move(ifTrue),
937cb93a386Sopenharmony_ci                ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
938cb93a386Sopenharmony_ci    } else {
939cb93a386Sopenharmony_ci        return If(std::move(test), std::move(ifTrue),
940cb93a386Sopenharmony_ci                ifFalse.hasValue() ? std::move(ifFalse) : DSLStatement(), this->position(start));
941cb93a386Sopenharmony_ci    }
942cb93a386Sopenharmony_ci}
943cb93a386Sopenharmony_ci
944cb93a386Sopenharmony_ci/* DO statement WHILE LPAREN expression RPAREN SEMICOLON */
945cb93a386Sopenharmony_ciDSLStatement DSLParser::doStatement() {
946cb93a386Sopenharmony_ci    Token start;
947cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_DO, "'do'", &start)) {
948cb93a386Sopenharmony_ci        return {};
949cb93a386Sopenharmony_ci    }
950cb93a386Sopenharmony_ci    DSLStatement statement = this->statement();
951cb93a386Sopenharmony_ci    if (!statement.hasValue()) {
952cb93a386Sopenharmony_ci        return {};
953cb93a386Sopenharmony_ci    }
954cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_WHILE, "'while'")) {
955cb93a386Sopenharmony_ci        return {};
956cb93a386Sopenharmony_ci    }
957cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
958cb93a386Sopenharmony_ci        return {};
959cb93a386Sopenharmony_ci    }
960cb93a386Sopenharmony_ci    DSLExpression test = this->expression();
961cb93a386Sopenharmony_ci    if (!test.hasValue()) {
962cb93a386Sopenharmony_ci        return {};
963cb93a386Sopenharmony_ci    }
964cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
965cb93a386Sopenharmony_ci        return {};
966cb93a386Sopenharmony_ci    }
967cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
968cb93a386Sopenharmony_ci        return {};
969cb93a386Sopenharmony_ci    }
970cb93a386Sopenharmony_ci    return Do(std::move(statement), std::move(test), this->position(start));
971cb93a386Sopenharmony_ci}
972cb93a386Sopenharmony_ci
973cb93a386Sopenharmony_ci/* WHILE LPAREN expression RPAREN STATEMENT */
974cb93a386Sopenharmony_ciDSLStatement DSLParser::whileStatement() {
975cb93a386Sopenharmony_ci    Token start;
976cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_WHILE, "'while'", &start)) {
977cb93a386Sopenharmony_ci        return {};
978cb93a386Sopenharmony_ci    }
979cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
980cb93a386Sopenharmony_ci        return {};
981cb93a386Sopenharmony_ci    }
982cb93a386Sopenharmony_ci    DSLExpression test = this->expression();
983cb93a386Sopenharmony_ci    if (!test.hasValue()) {
984cb93a386Sopenharmony_ci        return {};
985cb93a386Sopenharmony_ci    }
986cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
987cb93a386Sopenharmony_ci        return {};
988cb93a386Sopenharmony_ci    }
989cb93a386Sopenharmony_ci    DSLStatement statement = this->statement();
990cb93a386Sopenharmony_ci    if (!statement.hasValue()) {
991cb93a386Sopenharmony_ci        return {};
992cb93a386Sopenharmony_ci    }
993cb93a386Sopenharmony_ci    return While(std::move(test), std::move(statement), this->position(start));
994cb93a386Sopenharmony_ci}
995cb93a386Sopenharmony_ci
996cb93a386Sopenharmony_ci/* CASE expression COLON statement* */
997cb93a386Sopenharmony_ciskstd::optional<DSLCase> DSLParser::switchCase() {
998cb93a386Sopenharmony_ci    Token start;
999cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_CASE, "'case'", &start)) {
1000cb93a386Sopenharmony_ci        return {};
1001cb93a386Sopenharmony_ci    }
1002cb93a386Sopenharmony_ci    DSLExpression value = this->expression();
1003cb93a386Sopenharmony_ci    if (!value.hasValue()) {
1004cb93a386Sopenharmony_ci        return {};
1005cb93a386Sopenharmony_ci    }
1006cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1007cb93a386Sopenharmony_ci        return {};
1008cb93a386Sopenharmony_ci    }
1009cb93a386Sopenharmony_ci    SkTArray<DSLStatement> statements;
1010cb93a386Sopenharmony_ci    while (this->peek().fKind != Token::Kind::TK_RBRACE &&
1011cb93a386Sopenharmony_ci           this->peek().fKind != Token::Kind::TK_CASE &&
1012cb93a386Sopenharmony_ci           this->peek().fKind != Token::Kind::TK_DEFAULT) {
1013cb93a386Sopenharmony_ci        DSLStatement s = this->statement();
1014cb93a386Sopenharmony_ci        if (!s.hasValue()) {
1015cb93a386Sopenharmony_ci            return {};
1016cb93a386Sopenharmony_ci        }
1017cb93a386Sopenharmony_ci        statements.push_back(std::move(s));
1018cb93a386Sopenharmony_ci    }
1019cb93a386Sopenharmony_ci    return DSLCase(std::move(value), std::move(statements));
1020cb93a386Sopenharmony_ci}
1021cb93a386Sopenharmony_ci
1022cb93a386Sopenharmony_ci/* SWITCH LPAREN expression RPAREN LBRACE switchCase* (DEFAULT COLON statement*)? RBRACE */
1023cb93a386Sopenharmony_ciDSLStatement DSLParser::switchStatement() {
1024cb93a386Sopenharmony_ci    Token start;
1025cb93a386Sopenharmony_ci    bool isStatic = this->checkNext(Token::Kind::TK_STATIC_SWITCH, &start);
1026cb93a386Sopenharmony_ci    if (!isStatic && !this->expect(Token::Kind::TK_SWITCH, "'switch'", &start)) {
1027cb93a386Sopenharmony_ci        return {};
1028cb93a386Sopenharmony_ci    }
1029cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1030cb93a386Sopenharmony_ci        return {};
1031cb93a386Sopenharmony_ci    }
1032cb93a386Sopenharmony_ci    DSLExpression value = this->expression();
1033cb93a386Sopenharmony_ci    if (!value.hasValue()) {
1034cb93a386Sopenharmony_ci        return {};
1035cb93a386Sopenharmony_ci    }
1036cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1037cb93a386Sopenharmony_ci        return {};
1038cb93a386Sopenharmony_ci    }
1039cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
1040cb93a386Sopenharmony_ci        return {};
1041cb93a386Sopenharmony_ci    }
1042cb93a386Sopenharmony_ci    SkTArray<DSLCase> cases;
1043cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_CASE) {
1044cb93a386Sopenharmony_ci        skstd::optional<DSLCase> c = this->switchCase();
1045cb93a386Sopenharmony_ci        if (!c) {
1046cb93a386Sopenharmony_ci            return {};
1047cb93a386Sopenharmony_ci        }
1048cb93a386Sopenharmony_ci        cases.push_back(std::move(*c));
1049cb93a386Sopenharmony_ci    }
1050cb93a386Sopenharmony_ci    // Requiring default: to be last (in defiance of C and GLSL) was a deliberate decision. Other
1051cb93a386Sopenharmony_ci    // parts of the compiler may rely upon this assumption.
1052cb93a386Sopenharmony_ci    if (this->peek().fKind == Token::Kind::TK_DEFAULT) {
1053cb93a386Sopenharmony_ci        SkTArray<DSLStatement> statements;
1054cb93a386Sopenharmony_ci        Token defaultStart;
1055cb93a386Sopenharmony_ci        SkAssertResult(this->expect(Token::Kind::TK_DEFAULT, "'default'", &defaultStart));
1056cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_COLON, "':'")) {
1057cb93a386Sopenharmony_ci            return {};
1058cb93a386Sopenharmony_ci        }
1059cb93a386Sopenharmony_ci        while (this->peek().fKind != Token::Kind::TK_RBRACE) {
1060cb93a386Sopenharmony_ci            DSLStatement s = this->statement();
1061cb93a386Sopenharmony_ci            if (!s.hasValue()) {
1062cb93a386Sopenharmony_ci                return {};
1063cb93a386Sopenharmony_ci            }
1064cb93a386Sopenharmony_ci            statements.push_back(std::move(s));
1065cb93a386Sopenharmony_ci        }
1066cb93a386Sopenharmony_ci        cases.push_back(DSLCase(DSLExpression(), std::move(statements), this->position(start)));
1067cb93a386Sopenharmony_ci    }
1068cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
1069cb93a386Sopenharmony_ci        return {};
1070cb93a386Sopenharmony_ci    }
1071cb93a386Sopenharmony_ci    if (isStatic) {
1072cb93a386Sopenharmony_ci        return StaticSwitch(std::move(value), std::move(cases), this->position(start));
1073cb93a386Sopenharmony_ci    } else {
1074cb93a386Sopenharmony_ci        return Switch(std::move(value), std::move(cases), this->position(start));
1075cb93a386Sopenharmony_ci    }
1076cb93a386Sopenharmony_ci}
1077cb93a386Sopenharmony_ci
1078cb93a386Sopenharmony_ci/* FOR LPAREN (declaration | expression)? SEMICOLON expression? SEMICOLON expression? RPAREN
1079cb93a386Sopenharmony_ci   STATEMENT */
1080cb93a386Sopenharmony_cidsl::DSLStatement DSLParser::forStatement() {
1081cb93a386Sopenharmony_ci    Token start;
1082cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_FOR, "'for'", &start)) {
1083cb93a386Sopenharmony_ci        return {};
1084cb93a386Sopenharmony_ci    }
1085cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LPAREN, "'('")) {
1086cb93a386Sopenharmony_ci        return {};
1087cb93a386Sopenharmony_ci    }
1088cb93a386Sopenharmony_ci    AutoDSLSymbolTable symbols;
1089cb93a386Sopenharmony_ci    dsl::DSLStatement initializer;
1090cb93a386Sopenharmony_ci    Token nextToken = this->peek();
1091cb93a386Sopenharmony_ci    if (nextToken.fKind == Token::Kind::TK_SEMICOLON) {
1092cb93a386Sopenharmony_ci        // An empty init-statement.
1093cb93a386Sopenharmony_ci        this->nextToken();
1094cb93a386Sopenharmony_ci    } else {
1095cb93a386Sopenharmony_ci        // The init-statement must be an expression or variable declaration.
1096cb93a386Sopenharmony_ci        initializer = this->varDeclarationsOrExpressionStatement();
1097cb93a386Sopenharmony_ci        if (!initializer.hasValue()) {
1098cb93a386Sopenharmony_ci            return {};
1099cb93a386Sopenharmony_ci        }
1100cb93a386Sopenharmony_ci    }
1101cb93a386Sopenharmony_ci    dsl::DSLExpression test;
1102cb93a386Sopenharmony_ci    if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1103cb93a386Sopenharmony_ci        dsl::DSLExpression testValue = this->expression();
1104cb93a386Sopenharmony_ci        if (!testValue.hasValue()) {
1105cb93a386Sopenharmony_ci            return {};
1106cb93a386Sopenharmony_ci        }
1107cb93a386Sopenharmony_ci        test.swap(testValue);
1108cb93a386Sopenharmony_ci    }
1109cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1110cb93a386Sopenharmony_ci        return {};
1111cb93a386Sopenharmony_ci    }
1112cb93a386Sopenharmony_ci    dsl::DSLExpression next;
1113cb93a386Sopenharmony_ci    if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1114cb93a386Sopenharmony_ci        dsl::DSLExpression nextValue = this->expression();
1115cb93a386Sopenharmony_ci        if (!nextValue.hasValue()) {
1116cb93a386Sopenharmony_ci            return {};
1117cb93a386Sopenharmony_ci        }
1118cb93a386Sopenharmony_ci        next.swap(nextValue);
1119cb93a386Sopenharmony_ci    }
1120cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RPAREN, "')'")) {
1121cb93a386Sopenharmony_ci        return {};
1122cb93a386Sopenharmony_ci    }
1123cb93a386Sopenharmony_ci    dsl::DSLStatement statement = this->statement();
1124cb93a386Sopenharmony_ci    if (!statement.hasValue()) {
1125cb93a386Sopenharmony_ci        return {};
1126cb93a386Sopenharmony_ci    }
1127cb93a386Sopenharmony_ci    return For(initializer.hasValue() ? std::move(initializer) : DSLStatement(),
1128cb93a386Sopenharmony_ci               test.hasValue() ? std::move(test) : DSLExpression(),
1129cb93a386Sopenharmony_ci               next.hasValue() ? std::move(next) : DSLExpression(),
1130cb93a386Sopenharmony_ci               std::move(statement),
1131cb93a386Sopenharmony_ci               this->position(start));
1132cb93a386Sopenharmony_ci}
1133cb93a386Sopenharmony_ci
1134cb93a386Sopenharmony_ci/* RETURN expression? SEMICOLON */
1135cb93a386Sopenharmony_ciDSLStatement DSLParser::returnStatement() {
1136cb93a386Sopenharmony_ci    Token start;
1137cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_RETURN, "'return'", &start)) {
1138cb93a386Sopenharmony_ci        return {};
1139cb93a386Sopenharmony_ci    }
1140cb93a386Sopenharmony_ci    DSLExpression expression;
1141cb93a386Sopenharmony_ci    if (this->peek().fKind != Token::Kind::TK_SEMICOLON) {
1142cb93a386Sopenharmony_ci        DSLExpression next = this->expression();
1143cb93a386Sopenharmony_ci        if (!next.hasValue()) {
1144cb93a386Sopenharmony_ci            return {};
1145cb93a386Sopenharmony_ci        }
1146cb93a386Sopenharmony_ci        expression.swap(next);
1147cb93a386Sopenharmony_ci    }
1148cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1149cb93a386Sopenharmony_ci        return {};
1150cb93a386Sopenharmony_ci    }
1151cb93a386Sopenharmony_ci    return Return(expression.hasValue() ? std::move(expression) : DSLExpression(),
1152cb93a386Sopenharmony_ci            this->position(start));
1153cb93a386Sopenharmony_ci}
1154cb93a386Sopenharmony_ci
1155cb93a386Sopenharmony_ci/* BREAK SEMICOLON */
1156cb93a386Sopenharmony_ciDSLStatement DSLParser::breakStatement() {
1157cb93a386Sopenharmony_ci    Token start;
1158cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_BREAK, "'break'", &start)) {
1159cb93a386Sopenharmony_ci        return {};
1160cb93a386Sopenharmony_ci    }
1161cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1162cb93a386Sopenharmony_ci        return {};
1163cb93a386Sopenharmony_ci    }
1164cb93a386Sopenharmony_ci    return Break(this->position(start));
1165cb93a386Sopenharmony_ci}
1166cb93a386Sopenharmony_ci
1167cb93a386Sopenharmony_ci/* CONTINUE SEMICOLON */
1168cb93a386Sopenharmony_ciDSLStatement DSLParser::continueStatement() {
1169cb93a386Sopenharmony_ci    Token start;
1170cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_CONTINUE, "'continue'", &start)) {
1171cb93a386Sopenharmony_ci        return {};
1172cb93a386Sopenharmony_ci    }
1173cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1174cb93a386Sopenharmony_ci        return {};
1175cb93a386Sopenharmony_ci    }
1176cb93a386Sopenharmony_ci    return Continue(this->position(start));
1177cb93a386Sopenharmony_ci}
1178cb93a386Sopenharmony_ci
1179cb93a386Sopenharmony_ci/* DISCARD SEMICOLON */
1180cb93a386Sopenharmony_ciDSLStatement DSLParser::discardStatement() {
1181cb93a386Sopenharmony_ci    Token start;
1182cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_DISCARD, "'continue'", &start)) {
1183cb93a386Sopenharmony_ci        return {};
1184cb93a386Sopenharmony_ci    }
1185cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1186cb93a386Sopenharmony_ci        return {};
1187cb93a386Sopenharmony_ci    }
1188cb93a386Sopenharmony_ci    return Discard(this->position(start));
1189cb93a386Sopenharmony_ci}
1190cb93a386Sopenharmony_ci
1191cb93a386Sopenharmony_ci/* LBRACE statement* RBRACE */
1192cb93a386Sopenharmony_ciskstd::optional<DSLBlock> DSLParser::block() {
1193cb93a386Sopenharmony_ci    Token start;
1194cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_LBRACE, "'{'", &start)) {
1195cb93a386Sopenharmony_ci        return skstd::nullopt;
1196cb93a386Sopenharmony_ci    }
1197cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1198cb93a386Sopenharmony_ci    if (!depth.increase()) {
1199cb93a386Sopenharmony_ci        return skstd::nullopt;
1200cb93a386Sopenharmony_ci    }
1201cb93a386Sopenharmony_ci    AutoDSLSymbolTable symbols;
1202cb93a386Sopenharmony_ci    StatementArray statements;
1203cb93a386Sopenharmony_ci    for (;;) {
1204cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1205cb93a386Sopenharmony_ci            case Token::Kind::TK_RBRACE:
1206cb93a386Sopenharmony_ci                this->nextToken();
1207cb93a386Sopenharmony_ci                return DSLBlock(std::move(statements), CurrentSymbolTable());
1208cb93a386Sopenharmony_ci            case Token::Kind::TK_END_OF_FILE:
1209cb93a386Sopenharmony_ci                this->error(this->peek(), "expected '}', but found end of file");
1210cb93a386Sopenharmony_ci                return skstd::nullopt;
1211cb93a386Sopenharmony_ci            default: {
1212cb93a386Sopenharmony_ci                DSLStatement statement = this->statement();
1213cb93a386Sopenharmony_ci                if (!statement.hasValue()) {
1214cb93a386Sopenharmony_ci                    return skstd::nullopt;
1215cb93a386Sopenharmony_ci                }
1216cb93a386Sopenharmony_ci                statements.push_back(statement.release());
1217cb93a386Sopenharmony_ci                break;
1218cb93a386Sopenharmony_ci            }
1219cb93a386Sopenharmony_ci        }
1220cb93a386Sopenharmony_ci    }
1221cb93a386Sopenharmony_ci}
1222cb93a386Sopenharmony_ci
1223cb93a386Sopenharmony_ci/* expression SEMICOLON */
1224cb93a386Sopenharmony_ciDSLStatement DSLParser::expressionStatement() {
1225cb93a386Sopenharmony_ci    DSLExpression expr = this->expression();
1226cb93a386Sopenharmony_ci    if (expr.hasValue()) {
1227cb93a386Sopenharmony_ci        if (!this->expect(Token::Kind::TK_SEMICOLON, "';'")) {
1228cb93a386Sopenharmony_ci            return {};
1229cb93a386Sopenharmony_ci        }
1230cb93a386Sopenharmony_ci        return DSLStatement(std::move(expr));
1231cb93a386Sopenharmony_ci    }
1232cb93a386Sopenharmony_ci    return {};
1233cb93a386Sopenharmony_ci}
1234cb93a386Sopenharmony_ci
1235cb93a386Sopenharmony_ci/* assignmentExpression (COMMA assignmentExpression)* */
1236cb93a386Sopenharmony_ciDSLExpression DSLParser::expression() {
1237cb93a386Sopenharmony_ci    DSLExpression result = this->assignmentExpression();
1238cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1239cb93a386Sopenharmony_ci        return {};
1240cb93a386Sopenharmony_ci    }
1241cb93a386Sopenharmony_ci    Token t;
1242cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1243cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_COMMA, &t)) {
1244cb93a386Sopenharmony_ci        if (!depth.increase()) {
1245cb93a386Sopenharmony_ci            return {};
1246cb93a386Sopenharmony_ci        }
1247cb93a386Sopenharmony_ci        DSLExpression right = this->assignmentExpression();
1248cb93a386Sopenharmony_ci        if (!right.hasValue()) {
1249cb93a386Sopenharmony_ci            return {};
1250cb93a386Sopenharmony_ci        }
1251cb93a386Sopenharmony_ci        DSLExpression next = dsl::operator,(std::move(result), std::move(right));
1252cb93a386Sopenharmony_ci        result.swap(next);
1253cb93a386Sopenharmony_ci    }
1254cb93a386Sopenharmony_ci    return result;
1255cb93a386Sopenharmony_ci}
1256cb93a386Sopenharmony_ci
1257cb93a386Sopenharmony_ci#define OPERATOR_RIGHT(op, exprType)                                         \
1258cb93a386Sopenharmony_ci    do {                                                                     \
1259cb93a386Sopenharmony_ci        this->nextToken();                                                   \
1260cb93a386Sopenharmony_ci        if (!depth.increase()) {                                             \
1261cb93a386Sopenharmony_ci            return {};                                                       \
1262cb93a386Sopenharmony_ci        }                                                                    \
1263cb93a386Sopenharmony_ci        DSLExpression right = this->exprType();                              \
1264cb93a386Sopenharmony_ci        if (!right.hasValue()) {                                             \
1265cb93a386Sopenharmony_ci            return {};                                                       \
1266cb93a386Sopenharmony_ci        }                                                                    \
1267cb93a386Sopenharmony_ci        DSLExpression next = std::move(result) op std::move(right);          \
1268cb93a386Sopenharmony_ci        result.swap(next);                                                   \
1269cb93a386Sopenharmony_ci    } while (false)
1270cb93a386Sopenharmony_ci
1271cb93a386Sopenharmony_ci/* ternaryExpression ((EQEQ | STAREQ | SLASHEQ | PERCENTEQ | PLUSEQ | MINUSEQ | SHLEQ | SHREQ |
1272cb93a386Sopenharmony_ci   BITWISEANDEQ | BITWISEXOREQ | BITWISEOREQ | LOGICALANDEQ | LOGICALXOREQ | LOGICALOREQ)
1273cb93a386Sopenharmony_ci   assignmentExpression)*
1274cb93a386Sopenharmony_ci */
1275cb93a386Sopenharmony_ciDSLExpression DSLParser::assignmentExpression() {
1276cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1277cb93a386Sopenharmony_ci    DSLExpression result = this->ternaryExpression();
1278cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1279cb93a386Sopenharmony_ci        return {};
1280cb93a386Sopenharmony_ci    }
1281cb93a386Sopenharmony_ci    for (;;) {
1282cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1283cb93a386Sopenharmony_ci            case Token::Kind::TK_EQ:           OPERATOR_RIGHT(=,   assignmentExpression); break;
1284cb93a386Sopenharmony_ci            case Token::Kind::TK_STAREQ:       OPERATOR_RIGHT(*=,  assignmentExpression); break;
1285cb93a386Sopenharmony_ci            case Token::Kind::TK_SLASHEQ:      OPERATOR_RIGHT(/=,  assignmentExpression); break;
1286cb93a386Sopenharmony_ci            case Token::Kind::TK_PERCENTEQ:    OPERATOR_RIGHT(%=,  assignmentExpression); break;
1287cb93a386Sopenharmony_ci            case Token::Kind::TK_PLUSEQ:       OPERATOR_RIGHT(+=,  assignmentExpression); break;
1288cb93a386Sopenharmony_ci            case Token::Kind::TK_MINUSEQ:      OPERATOR_RIGHT(-=,  assignmentExpression); break;
1289cb93a386Sopenharmony_ci            case Token::Kind::TK_SHLEQ:        OPERATOR_RIGHT(<<=, assignmentExpression); break;
1290cb93a386Sopenharmony_ci            case Token::Kind::TK_SHREQ:        OPERATOR_RIGHT(>>=, assignmentExpression); break;
1291cb93a386Sopenharmony_ci            case Token::Kind::TK_BITWISEANDEQ: OPERATOR_RIGHT(&=,  assignmentExpression); break;
1292cb93a386Sopenharmony_ci            case Token::Kind::TK_BITWISEXOREQ: OPERATOR_RIGHT(^=,  assignmentExpression); break;
1293cb93a386Sopenharmony_ci            case Token::Kind::TK_BITWISEOREQ:  OPERATOR_RIGHT(|=,  assignmentExpression); break;
1294cb93a386Sopenharmony_ci            default:
1295cb93a386Sopenharmony_ci                return result;
1296cb93a386Sopenharmony_ci        }
1297cb93a386Sopenharmony_ci    }
1298cb93a386Sopenharmony_ci}
1299cb93a386Sopenharmony_ci
1300cb93a386Sopenharmony_ci/* logicalOrExpression ('?' expression ':' assignmentExpression)? */
1301cb93a386Sopenharmony_ciDSLExpression DSLParser::ternaryExpression() {
1302cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1303cb93a386Sopenharmony_ci    DSLExpression base = this->logicalOrExpression();
1304cb93a386Sopenharmony_ci    if (!base.hasValue()) {
1305cb93a386Sopenharmony_ci        return {};
1306cb93a386Sopenharmony_ci    }
1307cb93a386Sopenharmony_ci    if (this->checkNext(Token::Kind::TK_QUESTION)) {
1308cb93a386Sopenharmony_ci        if (!depth.increase()) {
1309cb93a386Sopenharmony_ci            return {};
1310cb93a386Sopenharmony_ci        }
1311cb93a386Sopenharmony_ci        DSLExpression trueExpr = this->expression();
1312cb93a386Sopenharmony_ci        if (!trueExpr.hasValue()) {
1313cb93a386Sopenharmony_ci            return {};
1314cb93a386Sopenharmony_ci        }
1315cb93a386Sopenharmony_ci        if (this->expect(Token::Kind::TK_COLON, "':'")) {
1316cb93a386Sopenharmony_ci            DSLExpression falseExpr = this->assignmentExpression();
1317cb93a386Sopenharmony_ci            if (!falseExpr.hasValue()) {
1318cb93a386Sopenharmony_ci                return {};
1319cb93a386Sopenharmony_ci            }
1320cb93a386Sopenharmony_ci            return Select(std::move(base), std::move(trueExpr), std::move(falseExpr));
1321cb93a386Sopenharmony_ci        }
1322cb93a386Sopenharmony_ci        return {};
1323cb93a386Sopenharmony_ci    }
1324cb93a386Sopenharmony_ci    return base;
1325cb93a386Sopenharmony_ci}
1326cb93a386Sopenharmony_ci
1327cb93a386Sopenharmony_ci/* logicalXorExpression (LOGICALOR logicalXorExpression)* */
1328cb93a386Sopenharmony_ciDSLExpression DSLParser::logicalOrExpression() {
1329cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1330cb93a386Sopenharmony_ci    DSLExpression result = this->logicalXorExpression();
1331cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1332cb93a386Sopenharmony_ci        return {};
1333cb93a386Sopenharmony_ci    }
1334cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_LOGICALOR) {
1335cb93a386Sopenharmony_ci        OPERATOR_RIGHT(||, logicalXorExpression);
1336cb93a386Sopenharmony_ci    }
1337cb93a386Sopenharmony_ci    return result;
1338cb93a386Sopenharmony_ci}
1339cb93a386Sopenharmony_ci
1340cb93a386Sopenharmony_ci/* logicalAndExpression (LOGICALXOR logicalAndExpression)* */
1341cb93a386Sopenharmony_ciDSLExpression DSLParser::logicalXorExpression() {
1342cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1343cb93a386Sopenharmony_ci    DSLExpression result = this->logicalAndExpression();
1344cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1345cb93a386Sopenharmony_ci        return {};
1346cb93a386Sopenharmony_ci    }
1347cb93a386Sopenharmony_ci    while (this->checkNext(Token::Kind::TK_LOGICALXOR)) {
1348cb93a386Sopenharmony_ci        if (!depth.increase()) {
1349cb93a386Sopenharmony_ci            return {};
1350cb93a386Sopenharmony_ci        }
1351cb93a386Sopenharmony_ci        DSLExpression right = this->logicalAndExpression();
1352cb93a386Sopenharmony_ci        if (!right.hasValue()) {
1353cb93a386Sopenharmony_ci            return {};
1354cb93a386Sopenharmony_ci        }
1355cb93a386Sopenharmony_ci        DSLExpression next = LogicalXor(std::move(result), std::move(right));
1356cb93a386Sopenharmony_ci        result.swap(next);
1357cb93a386Sopenharmony_ci    }
1358cb93a386Sopenharmony_ci    return result;
1359cb93a386Sopenharmony_ci}
1360cb93a386Sopenharmony_ci
1361cb93a386Sopenharmony_ci/* bitwiseOrExpression (LOGICALAND bitwiseOrExpression)* */
1362cb93a386Sopenharmony_ciDSLExpression DSLParser::logicalAndExpression() {
1363cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1364cb93a386Sopenharmony_ci    DSLExpression result = this->bitwiseOrExpression();
1365cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1366cb93a386Sopenharmony_ci        return {};
1367cb93a386Sopenharmony_ci    }
1368cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_LOGICALAND) {
1369cb93a386Sopenharmony_ci        OPERATOR_RIGHT(&&, bitwiseOrExpression);
1370cb93a386Sopenharmony_ci    }
1371cb93a386Sopenharmony_ci    return result;
1372cb93a386Sopenharmony_ci}
1373cb93a386Sopenharmony_ci
1374cb93a386Sopenharmony_ci/* bitwiseXorExpression (BITWISEOR bitwiseXorExpression)* */
1375cb93a386Sopenharmony_ciDSLExpression DSLParser::bitwiseOrExpression() {
1376cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1377cb93a386Sopenharmony_ci    DSLExpression result = this->bitwiseXorExpression();
1378cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1379cb93a386Sopenharmony_ci        return {};
1380cb93a386Sopenharmony_ci    }
1381cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_BITWISEOR) {
1382cb93a386Sopenharmony_ci        OPERATOR_RIGHT(|, bitwiseXorExpression);
1383cb93a386Sopenharmony_ci    }
1384cb93a386Sopenharmony_ci    return result;
1385cb93a386Sopenharmony_ci}
1386cb93a386Sopenharmony_ci
1387cb93a386Sopenharmony_ci/* bitwiseAndExpression (BITWISEXOR bitwiseAndExpression)* */
1388cb93a386Sopenharmony_ciDSLExpression DSLParser::bitwiseXorExpression() {
1389cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1390cb93a386Sopenharmony_ci    DSLExpression result = this->bitwiseAndExpression();
1391cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1392cb93a386Sopenharmony_ci        return {};
1393cb93a386Sopenharmony_ci    }
1394cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_BITWISEXOR) {
1395cb93a386Sopenharmony_ci        OPERATOR_RIGHT(^, bitwiseAndExpression);
1396cb93a386Sopenharmony_ci    }
1397cb93a386Sopenharmony_ci    return result;
1398cb93a386Sopenharmony_ci}
1399cb93a386Sopenharmony_ci
1400cb93a386Sopenharmony_ci/* equalityExpression (BITWISEAND equalityExpression)* */
1401cb93a386Sopenharmony_ciDSLExpression DSLParser::bitwiseAndExpression() {
1402cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1403cb93a386Sopenharmony_ci    DSLExpression result = this->equalityExpression();
1404cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1405cb93a386Sopenharmony_ci        return {};
1406cb93a386Sopenharmony_ci    }
1407cb93a386Sopenharmony_ci    while (this->peek().fKind == Token::Kind::TK_BITWISEAND) {
1408cb93a386Sopenharmony_ci        OPERATOR_RIGHT(&, equalityExpression);
1409cb93a386Sopenharmony_ci    }
1410cb93a386Sopenharmony_ci    return result;
1411cb93a386Sopenharmony_ci}
1412cb93a386Sopenharmony_ci
1413cb93a386Sopenharmony_ci/* relationalExpression ((EQEQ | NEQ) relationalExpression)* */
1414cb93a386Sopenharmony_ciDSLExpression DSLParser::equalityExpression() {
1415cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1416cb93a386Sopenharmony_ci    DSLExpression result = this->relationalExpression();
1417cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1418cb93a386Sopenharmony_ci        return {};
1419cb93a386Sopenharmony_ci    }
1420cb93a386Sopenharmony_ci    for (;;) {
1421cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1422cb93a386Sopenharmony_ci            case Token::Kind::TK_EQEQ: OPERATOR_RIGHT(==, relationalExpression); break;
1423cb93a386Sopenharmony_ci            case Token::Kind::TK_NEQ:  OPERATOR_RIGHT(!=, relationalExpression); break;
1424cb93a386Sopenharmony_ci            default: return result;
1425cb93a386Sopenharmony_ci        }
1426cb93a386Sopenharmony_ci    }
1427cb93a386Sopenharmony_ci}
1428cb93a386Sopenharmony_ci
1429cb93a386Sopenharmony_ci/* shiftExpression ((LT | GT | LTEQ | GTEQ) shiftExpression)* */
1430cb93a386Sopenharmony_ciDSLExpression DSLParser::relationalExpression() {
1431cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1432cb93a386Sopenharmony_ci    DSLExpression result = this->shiftExpression();
1433cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1434cb93a386Sopenharmony_ci        return {};
1435cb93a386Sopenharmony_ci    }
1436cb93a386Sopenharmony_ci    for (;;) {
1437cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1438cb93a386Sopenharmony_ci            case Token::Kind::TK_LT:   OPERATOR_RIGHT(<,  shiftExpression); break;
1439cb93a386Sopenharmony_ci            case Token::Kind::TK_GT:   OPERATOR_RIGHT(>,  shiftExpression); break;
1440cb93a386Sopenharmony_ci            case Token::Kind::TK_LTEQ: OPERATOR_RIGHT(<=, shiftExpression); break;
1441cb93a386Sopenharmony_ci            case Token::Kind::TK_GTEQ: OPERATOR_RIGHT(>=, shiftExpression); break;
1442cb93a386Sopenharmony_ci            default: return result;
1443cb93a386Sopenharmony_ci        }
1444cb93a386Sopenharmony_ci    }
1445cb93a386Sopenharmony_ci}
1446cb93a386Sopenharmony_ci
1447cb93a386Sopenharmony_ci/* additiveExpression ((SHL | SHR) additiveExpression)* */
1448cb93a386Sopenharmony_ciDSLExpression DSLParser::shiftExpression() {
1449cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1450cb93a386Sopenharmony_ci    DSLExpression result = this->additiveExpression();
1451cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1452cb93a386Sopenharmony_ci        return {};
1453cb93a386Sopenharmony_ci    }
1454cb93a386Sopenharmony_ci    for (;;) {
1455cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1456cb93a386Sopenharmony_ci            case Token::Kind::TK_SHL: OPERATOR_RIGHT(<<, additiveExpression); break;
1457cb93a386Sopenharmony_ci            case Token::Kind::TK_SHR: OPERATOR_RIGHT(>>, additiveExpression); break;
1458cb93a386Sopenharmony_ci            default: return result;
1459cb93a386Sopenharmony_ci        }
1460cb93a386Sopenharmony_ci    }
1461cb93a386Sopenharmony_ci}
1462cb93a386Sopenharmony_ci
1463cb93a386Sopenharmony_ci/* multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* */
1464cb93a386Sopenharmony_ciDSLExpression DSLParser::additiveExpression() {
1465cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1466cb93a386Sopenharmony_ci    DSLExpression result = this->multiplicativeExpression();
1467cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1468cb93a386Sopenharmony_ci        return {};
1469cb93a386Sopenharmony_ci    }
1470cb93a386Sopenharmony_ci    for (;;) {
1471cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1472cb93a386Sopenharmony_ci            case Token::Kind::TK_PLUS:  OPERATOR_RIGHT(+, multiplicativeExpression); break;
1473cb93a386Sopenharmony_ci            case Token::Kind::TK_MINUS: OPERATOR_RIGHT(-, multiplicativeExpression); break;
1474cb93a386Sopenharmony_ci            default: return result;
1475cb93a386Sopenharmony_ci        }
1476cb93a386Sopenharmony_ci    }
1477cb93a386Sopenharmony_ci}
1478cb93a386Sopenharmony_ci
1479cb93a386Sopenharmony_ci/* unaryExpression ((STAR | SLASH | PERCENT) unaryExpression)* */
1480cb93a386Sopenharmony_ciDSLExpression DSLParser::multiplicativeExpression() {
1481cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1482cb93a386Sopenharmony_ci    DSLExpression result = this->unaryExpression();
1483cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1484cb93a386Sopenharmony_ci        return {};
1485cb93a386Sopenharmony_ci    }
1486cb93a386Sopenharmony_ci    for (;;) {
1487cb93a386Sopenharmony_ci        switch (this->peek().fKind) {
1488cb93a386Sopenharmony_ci            case Token::Kind::TK_STAR:    OPERATOR_RIGHT(*, unaryExpression); break;
1489cb93a386Sopenharmony_ci            case Token::Kind::TK_SLASH:   OPERATOR_RIGHT(/, unaryExpression); break;
1490cb93a386Sopenharmony_ci            case Token::Kind::TK_PERCENT: OPERATOR_RIGHT(%, unaryExpression); break;
1491cb93a386Sopenharmony_ci            default: return result;
1492cb93a386Sopenharmony_ci        }
1493cb93a386Sopenharmony_ci    }
1494cb93a386Sopenharmony_ci}
1495cb93a386Sopenharmony_ci
1496cb93a386Sopenharmony_ci/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
1497cb93a386Sopenharmony_ciDSLExpression DSLParser::unaryExpression() {
1498cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1499cb93a386Sopenharmony_ci    Token next = this->peek();
1500cb93a386Sopenharmony_ci    switch (next.fKind) {
1501cb93a386Sopenharmony_ci        case Token::Kind::TK_PLUS:
1502cb93a386Sopenharmony_ci        case Token::Kind::TK_MINUS:
1503cb93a386Sopenharmony_ci        case Token::Kind::TK_LOGICALNOT:
1504cb93a386Sopenharmony_ci        case Token::Kind::TK_BITWISENOT:
1505cb93a386Sopenharmony_ci        case Token::Kind::TK_PLUSPLUS:
1506cb93a386Sopenharmony_ci        case Token::Kind::TK_MINUSMINUS: {
1507cb93a386Sopenharmony_ci            if (!depth.increase()) {
1508cb93a386Sopenharmony_ci                return {};
1509cb93a386Sopenharmony_ci            }
1510cb93a386Sopenharmony_ci            this->nextToken();
1511cb93a386Sopenharmony_ci            DSLExpression expr = this->unaryExpression();
1512cb93a386Sopenharmony_ci            if (!expr.hasValue()) {
1513cb93a386Sopenharmony_ci                return {};
1514cb93a386Sopenharmony_ci            }
1515cb93a386Sopenharmony_ci            switch (next.fKind) {
1516cb93a386Sopenharmony_ci                case Token::Kind::TK_PLUS:       return {{ +std::move(expr)}};
1517cb93a386Sopenharmony_ci                case Token::Kind::TK_MINUS:      return {{ -std::move(expr)}};
1518cb93a386Sopenharmony_ci                case Token::Kind::TK_LOGICALNOT: return {{ !std::move(expr)}};
1519cb93a386Sopenharmony_ci                case Token::Kind::TK_BITWISENOT: return {{ ~std::move(expr)}};
1520cb93a386Sopenharmony_ci                case Token::Kind::TK_PLUSPLUS:   return {{++std::move(expr)}};
1521cb93a386Sopenharmony_ci                case Token::Kind::TK_MINUSMINUS: return {{--std::move(expr)}};
1522cb93a386Sopenharmony_ci                default: SkUNREACHABLE;
1523cb93a386Sopenharmony_ci            }
1524cb93a386Sopenharmony_ci        }
1525cb93a386Sopenharmony_ci        default:
1526cb93a386Sopenharmony_ci            return this->postfixExpression();
1527cb93a386Sopenharmony_ci    }
1528cb93a386Sopenharmony_ci}
1529cb93a386Sopenharmony_ci
1530cb93a386Sopenharmony_ci/* term suffix* */
1531cb93a386Sopenharmony_ciDSLExpression DSLParser::postfixExpression() {
1532cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1533cb93a386Sopenharmony_ci    DSLExpression result = this->term();
1534cb93a386Sopenharmony_ci    if (!result.hasValue()) {
1535cb93a386Sopenharmony_ci        return {};
1536cb93a386Sopenharmony_ci    }
1537cb93a386Sopenharmony_ci    for (;;) {
1538cb93a386Sopenharmony_ci        Token t = this->peek();
1539cb93a386Sopenharmony_ci        switch (t.fKind) {
1540cb93a386Sopenharmony_ci            case Token::Kind::TK_FLOAT_LITERAL:
1541cb93a386Sopenharmony_ci                if (this->text(t)[0] != '.') {
1542cb93a386Sopenharmony_ci                    return result;
1543cb93a386Sopenharmony_ci                }
1544cb93a386Sopenharmony_ci                [[fallthrough]];
1545cb93a386Sopenharmony_ci            case Token::Kind::TK_LBRACKET:
1546cb93a386Sopenharmony_ci            case Token::Kind::TK_DOT:
1547cb93a386Sopenharmony_ci            case Token::Kind::TK_LPAREN:
1548cb93a386Sopenharmony_ci            case Token::Kind::TK_PLUSPLUS:
1549cb93a386Sopenharmony_ci            case Token::Kind::TK_MINUSMINUS: {
1550cb93a386Sopenharmony_ci                if (!depth.increase()) {
1551cb93a386Sopenharmony_ci                    return {};
1552cb93a386Sopenharmony_ci                }
1553cb93a386Sopenharmony_ci                DSLExpression next = this->suffix(std::move(result));
1554cb93a386Sopenharmony_ci                if (!next.hasValue()) {
1555cb93a386Sopenharmony_ci                    return {};
1556cb93a386Sopenharmony_ci                }
1557cb93a386Sopenharmony_ci                result.swap(next);
1558cb93a386Sopenharmony_ci                break;
1559cb93a386Sopenharmony_ci            }
1560cb93a386Sopenharmony_ci            default:
1561cb93a386Sopenharmony_ci                return result;
1562cb93a386Sopenharmony_ci        }
1563cb93a386Sopenharmony_ci    }
1564cb93a386Sopenharmony_ci}
1565cb93a386Sopenharmony_ci
1566cb93a386Sopenharmony_ciDSLExpression DSLParser::swizzle(int line, DSLExpression base,
1567cb93a386Sopenharmony_ci        skstd::string_view swizzleMask) {
1568cb93a386Sopenharmony_ci    SkASSERT(swizzleMask.length() > 0);
1569cb93a386Sopenharmony_ci    if (!base.type().isVector() && !base.type().isScalar()) {
1570cb93a386Sopenharmony_ci        return base.field(swizzleMask, this->position(line));
1571cb93a386Sopenharmony_ci    }
1572cb93a386Sopenharmony_ci    int length = swizzleMask.length();
1573cb93a386Sopenharmony_ci    SkSL::SwizzleComponent::Type components[4];
1574cb93a386Sopenharmony_ci    for (int i = 0; i < length; ++i) {
1575cb93a386Sopenharmony_ci        if (i >= 4) {
1576cb93a386Sopenharmony_ci            this->error(line, "too many components in swizzle mask");
1577cb93a386Sopenharmony_ci            return DSLExpression::Poison();
1578cb93a386Sopenharmony_ci        }
1579cb93a386Sopenharmony_ci        switch (swizzleMask[i]) {
1580cb93a386Sopenharmony_ci            case '0': components[i] = SwizzleComponent::ZERO; break;
1581cb93a386Sopenharmony_ci            case '1': components[i] = SwizzleComponent::ONE;  break;
1582cb93a386Sopenharmony_ci            case 'r': components[i] = SwizzleComponent::R;    break;
1583cb93a386Sopenharmony_ci            case 'x': components[i] = SwizzleComponent::X;    break;
1584cb93a386Sopenharmony_ci            case 's': components[i] = SwizzleComponent::S;    break;
1585cb93a386Sopenharmony_ci            case 'L': components[i] = SwizzleComponent::UL;   break;
1586cb93a386Sopenharmony_ci            case 'g': components[i] = SwizzleComponent::G;    break;
1587cb93a386Sopenharmony_ci            case 'y': components[i] = SwizzleComponent::Y;    break;
1588cb93a386Sopenharmony_ci            case 't': components[i] = SwizzleComponent::T;    break;
1589cb93a386Sopenharmony_ci            case 'T': components[i] = SwizzleComponent::UT;   break;
1590cb93a386Sopenharmony_ci            case 'b': components[i] = SwizzleComponent::B;    break;
1591cb93a386Sopenharmony_ci            case 'z': components[i] = SwizzleComponent::Z;    break;
1592cb93a386Sopenharmony_ci            case 'p': components[i] = SwizzleComponent::P;    break;
1593cb93a386Sopenharmony_ci            case 'R': components[i] = SwizzleComponent::UR;   break;
1594cb93a386Sopenharmony_ci            case 'a': components[i] = SwizzleComponent::A;    break;
1595cb93a386Sopenharmony_ci            case 'w': components[i] = SwizzleComponent::W;    break;
1596cb93a386Sopenharmony_ci            case 'q': components[i] = SwizzleComponent::Q;    break;
1597cb93a386Sopenharmony_ci            case 'B': components[i] = SwizzleComponent::UB;   break;
1598cb93a386Sopenharmony_ci            default:
1599cb93a386Sopenharmony_ci                this->error(line,
1600cb93a386Sopenharmony_ci                        String::printf("invalid swizzle component '%c'", swizzleMask[i]).c_str());
1601cb93a386Sopenharmony_ci                return DSLExpression::Poison();
1602cb93a386Sopenharmony_ci        }
1603cb93a386Sopenharmony_ci    }
1604cb93a386Sopenharmony_ci    switch (length) {
1605cb93a386Sopenharmony_ci        case 1: return dsl::Swizzle(std::move(base), components[0]);
1606cb93a386Sopenharmony_ci        case 2: return dsl::Swizzle(std::move(base), components[0], components[1]);
1607cb93a386Sopenharmony_ci        case 3: return dsl::Swizzle(std::move(base), components[0], components[1], components[2]);
1608cb93a386Sopenharmony_ci        case 4: return dsl::Swizzle(std::move(base), components[0], components[1], components[2],
1609cb93a386Sopenharmony_ci                                    components[3]);
1610cb93a386Sopenharmony_ci        default: SkUNREACHABLE;
1611cb93a386Sopenharmony_ci    }
1612cb93a386Sopenharmony_ci}
1613cb93a386Sopenharmony_ci
1614cb93a386Sopenharmony_cidsl::DSLExpression DSLParser::call(int line, dsl::DSLExpression base, ExpressionArray args) {
1615cb93a386Sopenharmony_ci    return DSLExpression(base(std::move(args), this->position(line)), this->position(line));
1616cb93a386Sopenharmony_ci}
1617cb93a386Sopenharmony_ci
1618cb93a386Sopenharmony_ci/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN arguments RPAREN |
1619cb93a386Sopenharmony_ci   PLUSPLUS | MINUSMINUS | COLONCOLON IDENTIFIER | FLOAT_LITERAL [IDENTIFIER] */
1620cb93a386Sopenharmony_ciDSLExpression DSLParser::suffix(DSLExpression base) {
1621cb93a386Sopenharmony_ci    Token next = this->nextToken();
1622cb93a386Sopenharmony_ci    AutoDSLDepth depth(this);
1623cb93a386Sopenharmony_ci    if (!depth.increase()) {
1624cb93a386Sopenharmony_ci        return {};
1625cb93a386Sopenharmony_ci    }
1626cb93a386Sopenharmony_ci    switch (next.fKind) {
1627cb93a386Sopenharmony_ci        case Token::Kind::TK_LBRACKET: {
1628cb93a386Sopenharmony_ci            if (this->checkNext(Token::Kind::TK_RBRACKET)) {
1629cb93a386Sopenharmony_ci                this->error(next, "missing index in '[]'");
1630cb93a386Sopenharmony_ci                return DSLExpression::Poison();
1631cb93a386Sopenharmony_ci            }
1632cb93a386Sopenharmony_ci            DSLExpression index = this->expression();
1633cb93a386Sopenharmony_ci            if (!index.hasValue()) {
1634cb93a386Sopenharmony_ci                return {};
1635cb93a386Sopenharmony_ci            }
1636cb93a386Sopenharmony_ci            this->expect(Token::Kind::TK_RBRACKET, "']' to complete array access expression");
1637cb93a386Sopenharmony_ci            DSLPossibleExpression result = base[std::move(index)];
1638cb93a386Sopenharmony_ci            if (!result.valid()) {
1639cb93a386Sopenharmony_ci                result.reportErrors(this->position(next));
1640cb93a386Sopenharmony_ci            }
1641cb93a386Sopenharmony_ci            return std::move(result);
1642cb93a386Sopenharmony_ci        }
1643cb93a386Sopenharmony_ci        case Token::Kind::TK_DOT: {
1644cb93a386Sopenharmony_ci            int line = this->peek().fLine;
1645cb93a386Sopenharmony_ci            skstd::string_view text;
1646cb93a386Sopenharmony_ci            if (this->identifier(&text)) {
1647cb93a386Sopenharmony_ci                return this->swizzle(line, std::move(base), text);
1648cb93a386Sopenharmony_ci            }
1649cb93a386Sopenharmony_ci            [[fallthrough]];
1650cb93a386Sopenharmony_ci        }
1651cb93a386Sopenharmony_ci        case Token::Kind::TK_FLOAT_LITERAL: {
1652cb93a386Sopenharmony_ci            // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as
1653cb93a386Sopenharmony_ci            // floating point literals, possibly followed by an identifier. Handle that here.
1654cb93a386Sopenharmony_ci            skstd::string_view field = this->text(next);
1655cb93a386Sopenharmony_ci            SkASSERT(field[0] == '.');
1656cb93a386Sopenharmony_ci            field.remove_prefix(1);
1657cb93a386Sopenharmony_ci            // use the next *raw* token so we don't ignore whitespace - we only care about
1658cb93a386Sopenharmony_ci            // identifiers that directly follow the float
1659cb93a386Sopenharmony_ci            Token id = this->nextRawToken();
1660cb93a386Sopenharmony_ci            if (id.fKind == Token::Kind::TK_IDENTIFIER) {
1661cb93a386Sopenharmony_ci                return this->swizzle(next.fLine, std::move(base), field + this->text(id));
1662cb93a386Sopenharmony_ci            } else if (field.empty()) {
1663cb93a386Sopenharmony_ci                this->error(next, "expected field name or swizzle mask after '.'");
1664cb93a386Sopenharmony_ci                return {{DSLExpression::Poison()}};
1665cb93a386Sopenharmony_ci            }
1666cb93a386Sopenharmony_ci            this->pushback(id);
1667cb93a386Sopenharmony_ci            return this->swizzle(next.fLine, std::move(base), field);
1668cb93a386Sopenharmony_ci        }
1669cb93a386Sopenharmony_ci        case Token::Kind::TK_LPAREN: {
1670cb93a386Sopenharmony_ci            ExpressionArray args;
1671cb93a386Sopenharmony_ci            if (this->peek().fKind != Token::Kind::TK_RPAREN) {
1672cb93a386Sopenharmony_ci                for (;;) {
1673cb93a386Sopenharmony_ci                    DSLExpression expr = this->assignmentExpression();
1674cb93a386Sopenharmony_ci                    if (!expr.hasValue()) {
1675cb93a386Sopenharmony_ci                        return {};
1676cb93a386Sopenharmony_ci                    }
1677cb93a386Sopenharmony_ci                    args.push_back(expr.release());
1678cb93a386Sopenharmony_ci                    if (!this->checkNext(Token::Kind::TK_COMMA)) {
1679cb93a386Sopenharmony_ci                        break;
1680cb93a386Sopenharmony_ci                    }
1681cb93a386Sopenharmony_ci                }
1682cb93a386Sopenharmony_ci            }
1683cb93a386Sopenharmony_ci            this->expect(Token::Kind::TK_RPAREN, "')' to complete function arguments");
1684cb93a386Sopenharmony_ci            return this->call(next.fLine, std::move(base), std::move(args));
1685cb93a386Sopenharmony_ci        }
1686cb93a386Sopenharmony_ci        case Token::Kind::TK_PLUSPLUS:
1687cb93a386Sopenharmony_ci            return std::move(base)++;
1688cb93a386Sopenharmony_ci        case Token::Kind::TK_MINUSMINUS:
1689cb93a386Sopenharmony_ci            return std::move(base)--;
1690cb93a386Sopenharmony_ci        default: {
1691cb93a386Sopenharmony_ci            this->error(next,  "expected expression suffix, but found '" + this->text(next) + "'");
1692cb93a386Sopenharmony_ci            return {};
1693cb93a386Sopenharmony_ci        }
1694cb93a386Sopenharmony_ci    }
1695cb93a386Sopenharmony_ci}
1696cb93a386Sopenharmony_ci
1697cb93a386Sopenharmony_ci/* IDENTIFIER | intLiteral | floatLiteral | boolLiteral | '(' expression ')' */
1698cb93a386Sopenharmony_ciDSLExpression DSLParser::term() {
1699cb93a386Sopenharmony_ci    Token t = this->peek();
1700cb93a386Sopenharmony_ci    switch (t.fKind) {
1701cb93a386Sopenharmony_ci        case Token::Kind::TK_IDENTIFIER: {
1702cb93a386Sopenharmony_ci            skstd::string_view text;
1703cb93a386Sopenharmony_ci            if (this->identifier(&text)) {
1704cb93a386Sopenharmony_ci                return dsl::Symbol(text, this->position(t));
1705cb93a386Sopenharmony_ci            }
1706cb93a386Sopenharmony_ci            break;
1707cb93a386Sopenharmony_ci        }
1708cb93a386Sopenharmony_ci        case Token::Kind::TK_INT_LITERAL: {
1709cb93a386Sopenharmony_ci            SKSL_INT i;
1710cb93a386Sopenharmony_ci            if (!this->intLiteral(&i)) {
1711cb93a386Sopenharmony_ci                i = 0;
1712cb93a386Sopenharmony_ci            }
1713cb93a386Sopenharmony_ci            return DSLExpression(i, this->position(t));
1714cb93a386Sopenharmony_ci        }
1715cb93a386Sopenharmony_ci        case Token::Kind::TK_FLOAT_LITERAL: {
1716cb93a386Sopenharmony_ci            SKSL_FLOAT f;
1717cb93a386Sopenharmony_ci            if (!this->floatLiteral(&f)) {
1718cb93a386Sopenharmony_ci                f = 0.0f;
1719cb93a386Sopenharmony_ci            }
1720cb93a386Sopenharmony_ci            return DSLExpression(f, this->position(t));
1721cb93a386Sopenharmony_ci        }
1722cb93a386Sopenharmony_ci        case Token::Kind::TK_TRUE_LITERAL: // fall through
1723cb93a386Sopenharmony_ci        case Token::Kind::TK_FALSE_LITERAL: {
1724cb93a386Sopenharmony_ci            bool b;
1725cb93a386Sopenharmony_ci            SkAssertResult(this->boolLiteral(&b));
1726cb93a386Sopenharmony_ci            return DSLExpression(b, this->position(t));
1727cb93a386Sopenharmony_ci        }
1728cb93a386Sopenharmony_ci        case Token::Kind::TK_LPAREN: {
1729cb93a386Sopenharmony_ci            this->nextToken();
1730cb93a386Sopenharmony_ci            AutoDSLDepth depth(this);
1731cb93a386Sopenharmony_ci            if (!depth.increase()) {
1732cb93a386Sopenharmony_ci                return {};
1733cb93a386Sopenharmony_ci            }
1734cb93a386Sopenharmony_ci            DSLExpression result = this->expression();
1735cb93a386Sopenharmony_ci            if (result.hasValue()) {
1736cb93a386Sopenharmony_ci                this->expect(Token::Kind::TK_RPAREN, "')' to complete expression");
1737cb93a386Sopenharmony_ci                return result;
1738cb93a386Sopenharmony_ci            }
1739cb93a386Sopenharmony_ci            break;
1740cb93a386Sopenharmony_ci        }
1741cb93a386Sopenharmony_ci        default:
1742cb93a386Sopenharmony_ci            this->nextToken();
1743cb93a386Sopenharmony_ci            this->error(t, "expected expression, but found '" + this->text(t) + "'");
1744cb93a386Sopenharmony_ci            fEncounteredFatalError = true;
1745cb93a386Sopenharmony_ci            break;
1746cb93a386Sopenharmony_ci    }
1747cb93a386Sopenharmony_ci    return {};
1748cb93a386Sopenharmony_ci}
1749cb93a386Sopenharmony_ci
1750cb93a386Sopenharmony_ci/* INT_LITERAL */
1751cb93a386Sopenharmony_cibool DSLParser::intLiteral(SKSL_INT* dest) {
1752cb93a386Sopenharmony_ci    Token t;
1753cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_INT_LITERAL, "integer literal", &t)) {
1754cb93a386Sopenharmony_ci        return false;
1755cb93a386Sopenharmony_ci    }
1756cb93a386Sopenharmony_ci    skstd::string_view s = this->text(t);
1757cb93a386Sopenharmony_ci    if (!SkSL::stoi(s, dest)) {
1758cb93a386Sopenharmony_ci        this->error(t, "integer is too large: " + s);
1759cb93a386Sopenharmony_ci        return false;
1760cb93a386Sopenharmony_ci    }
1761cb93a386Sopenharmony_ci    return true;
1762cb93a386Sopenharmony_ci}
1763cb93a386Sopenharmony_ci
1764cb93a386Sopenharmony_ci/* FLOAT_LITERAL */
1765cb93a386Sopenharmony_cibool DSLParser::floatLiteral(SKSL_FLOAT* dest) {
1766cb93a386Sopenharmony_ci    Token t;
1767cb93a386Sopenharmony_ci    if (!this->expect(Token::Kind::TK_FLOAT_LITERAL, "float literal", &t)) {
1768cb93a386Sopenharmony_ci        return false;
1769cb93a386Sopenharmony_ci    }
1770cb93a386Sopenharmony_ci    skstd::string_view s = this->text(t);
1771cb93a386Sopenharmony_ci    if (!SkSL::stod(s, dest)) {
1772cb93a386Sopenharmony_ci        this->error(t, "floating-point value is too large: " + s);
1773cb93a386Sopenharmony_ci        return false;
1774cb93a386Sopenharmony_ci    }
1775cb93a386Sopenharmony_ci    return true;
1776cb93a386Sopenharmony_ci}
1777cb93a386Sopenharmony_ci
1778cb93a386Sopenharmony_ci/* TRUE_LITERAL | FALSE_LITERAL */
1779cb93a386Sopenharmony_cibool DSLParser::boolLiteral(bool* dest) {
1780cb93a386Sopenharmony_ci    Token t = this->nextToken();
1781cb93a386Sopenharmony_ci    switch (t.fKind) {
1782cb93a386Sopenharmony_ci        case Token::Kind::TK_TRUE_LITERAL:
1783cb93a386Sopenharmony_ci            *dest = true;
1784cb93a386Sopenharmony_ci            return true;
1785cb93a386Sopenharmony_ci        case Token::Kind::TK_FALSE_LITERAL:
1786cb93a386Sopenharmony_ci            *dest = false;
1787cb93a386Sopenharmony_ci            return true;
1788cb93a386Sopenharmony_ci        default:
1789cb93a386Sopenharmony_ci            this->error(t, "expected 'true' or 'false', but found '" + this->text(t) + "'");
1790cb93a386Sopenharmony_ci            return false;
1791cb93a386Sopenharmony_ci    }
1792cb93a386Sopenharmony_ci}
1793cb93a386Sopenharmony_ci
1794cb93a386Sopenharmony_ci/* IDENTIFIER */
1795cb93a386Sopenharmony_cibool DSLParser::identifier(skstd::string_view* dest) {
1796cb93a386Sopenharmony_ci    Token t;
1797cb93a386Sopenharmony_ci    if (this->expect(Token::Kind::TK_IDENTIFIER, "identifier", &t)) {
1798cb93a386Sopenharmony_ci        *dest = this->text(t);
1799cb93a386Sopenharmony_ci        return true;
1800cb93a386Sopenharmony_ci    }
1801cb93a386Sopenharmony_ci    return false;
1802cb93a386Sopenharmony_ci}
1803cb93a386Sopenharmony_ci
1804cb93a386Sopenharmony_ci}  // namespace SkSL
1805