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(¶m.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