15cd3d5c8SMarek Sokolowski //===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===// 25cd3d5c8SMarek Sokolowski // 35cd3d5c8SMarek Sokolowski // The LLVM Compiler Infrastructure 45cd3d5c8SMarek Sokolowski // 55cd3d5c8SMarek Sokolowski // This file is distributed under the University of Illinois Open Source 65cd3d5c8SMarek Sokolowski // License. See LICENSE.TXT for details. 75cd3d5c8SMarek Sokolowski // 85cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===// 95cd3d5c8SMarek Sokolowski // 105cd3d5c8SMarek Sokolowski // This implements the parser defined in ResourceScriptParser.h. 115cd3d5c8SMarek Sokolowski // 125cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===// 135cd3d5c8SMarek Sokolowski 145cd3d5c8SMarek Sokolowski #include "ResourceScriptParser.h" 155cd3d5c8SMarek Sokolowski 165cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Error and forward the error if it exists. 175cd3d5c8SMarek Sokolowski #define RETURN_IF_ERROR(Expr) \ 185cd3d5c8SMarek Sokolowski if (auto Err = (Expr)) \ 195cd3d5c8SMarek Sokolowski return std::move(Err); 205cd3d5c8SMarek Sokolowski 215cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Expected<T> and assign it to Var or 225cd3d5c8SMarek Sokolowski // forward the error out of the function. 235cd3d5c8SMarek Sokolowski #define ASSIGN_OR_RETURN(Var, Expr) \ 245cd3d5c8SMarek Sokolowski auto Var = (Expr); \ 255cd3d5c8SMarek Sokolowski if (!Var) \ 265cd3d5c8SMarek Sokolowski return Var.takeError(); 275cd3d5c8SMarek Sokolowski 285cd3d5c8SMarek Sokolowski namespace llvm { 295cd3d5c8SMarek Sokolowski namespace rc { 305cd3d5c8SMarek Sokolowski 315cd3d5c8SMarek Sokolowski RCParser::ParserError::ParserError(const Twine Expected, const LocIter CurLoc, 325cd3d5c8SMarek Sokolowski const LocIter End) 335cd3d5c8SMarek Sokolowski : ErrorLoc(CurLoc), FileEnd(End) { 345cd3d5c8SMarek Sokolowski CurMessage = "Error parsing file: expected " + Expected.str() + ", got " + 355cd3d5c8SMarek Sokolowski (CurLoc == End ? "<EOF>" : CurLoc->value()).str(); 365cd3d5c8SMarek Sokolowski } 375cd3d5c8SMarek Sokolowski 385cd3d5c8SMarek Sokolowski char RCParser::ParserError::ID = 0; 395cd3d5c8SMarek Sokolowski 405cd3d5c8SMarek Sokolowski RCParser::RCParser(const std::vector<RCToken> &TokenList) 415cd3d5c8SMarek Sokolowski : Tokens(TokenList), CurLoc(Tokens.begin()), End(Tokens.end()) {} 425cd3d5c8SMarek Sokolowski 435cd3d5c8SMarek Sokolowski RCParser::RCParser(std::vector<RCToken> &&TokenList) 445cd3d5c8SMarek Sokolowski : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {} 455cd3d5c8SMarek Sokolowski 465cd3d5c8SMarek Sokolowski bool RCParser::isEof() const { return CurLoc == End; } 475cd3d5c8SMarek Sokolowski 485cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseSingleResource() { 495cd3d5c8SMarek Sokolowski // The first thing we read is usually a resource's name. However, in some 505cd3d5c8SMarek Sokolowski // cases (LANGUAGE and STRINGTABLE) the resources don't have their names 515cd3d5c8SMarek Sokolowski // and the first token to be read is the type. 525cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(NameToken, readTypeOrName()); 535cd3d5c8SMarek Sokolowski 545cd3d5c8SMarek Sokolowski if (NameToken->equalsLower("LANGUAGE")) 555cd3d5c8SMarek Sokolowski return parseLanguageResource(); 565cd3d5c8SMarek Sokolowski else if (NameToken->equalsLower("STRINGTABLE")) 575cd3d5c8SMarek Sokolowski return parseStringTableResource(); 585cd3d5c8SMarek Sokolowski 595cd3d5c8SMarek Sokolowski // If it's not an unnamed resource, what we've just read is a name. Now, 605cd3d5c8SMarek Sokolowski // read resource type; 615cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(TypeToken, readTypeOrName()); 625cd3d5c8SMarek Sokolowski 635cd3d5c8SMarek Sokolowski ParseType Result = std::unique_ptr<RCResource>(); 645cd3d5c8SMarek Sokolowski (void)!Result; 655cd3d5c8SMarek Sokolowski 667f110527SMarek Sokolowski if (TypeToken->equalsLower("ACCELERATORS")) 677f110527SMarek Sokolowski Result = parseAcceleratorsResource(); 687f110527SMarek Sokolowski else if (TypeToken->equalsLower("CURSOR")) 6972aa937eSMarek Sokolowski Result = parseCursorResource(); 7072aa937eSMarek Sokolowski else if (TypeToken->equalsLower("ICON")) 715cd3d5c8SMarek Sokolowski Result = parseIconResource(); 7272aa937eSMarek Sokolowski else if (TypeToken->equalsLower("HTML")) 7372aa937eSMarek Sokolowski Result = parseHTMLResource(); 74*99ecb0ebSMarek Sokolowski else if (TypeToken->equalsLower("MENU")) 75*99ecb0ebSMarek Sokolowski Result = parseMenuResource(); 765cd3d5c8SMarek Sokolowski else 775cd3d5c8SMarek Sokolowski return getExpectedError("resource type", /* IsAlreadyRead = */ true); 785cd3d5c8SMarek Sokolowski 795cd3d5c8SMarek Sokolowski if (Result) 805cd3d5c8SMarek Sokolowski (*Result)->setName(*NameToken); 815cd3d5c8SMarek Sokolowski 825cd3d5c8SMarek Sokolowski return Result; 835cd3d5c8SMarek Sokolowski } 845cd3d5c8SMarek Sokolowski 855cd3d5c8SMarek Sokolowski bool RCParser::isNextTokenKind(Kind TokenKind) const { 865cd3d5c8SMarek Sokolowski return !isEof() && look().kind() == TokenKind; 875cd3d5c8SMarek Sokolowski } 885cd3d5c8SMarek Sokolowski 895cd3d5c8SMarek Sokolowski const RCToken &RCParser::look() const { 905cd3d5c8SMarek Sokolowski assert(!isEof()); 915cd3d5c8SMarek Sokolowski return *CurLoc; 925cd3d5c8SMarek Sokolowski } 935cd3d5c8SMarek Sokolowski 945cd3d5c8SMarek Sokolowski const RCToken &RCParser::read() { 955cd3d5c8SMarek Sokolowski assert(!isEof()); 965cd3d5c8SMarek Sokolowski return *CurLoc++; 975cd3d5c8SMarek Sokolowski } 985cd3d5c8SMarek Sokolowski 995cd3d5c8SMarek Sokolowski void RCParser::consume() { 1005cd3d5c8SMarek Sokolowski assert(!isEof()); 1015cd3d5c8SMarek Sokolowski CurLoc++; 1025cd3d5c8SMarek Sokolowski } 1035cd3d5c8SMarek Sokolowski 1045cd3d5c8SMarek Sokolowski Expected<uint32_t> RCParser::readInt() { 1055cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Int)) 1065cd3d5c8SMarek Sokolowski return getExpectedError("integer"); 1075cd3d5c8SMarek Sokolowski return read().intValue(); 1085cd3d5c8SMarek Sokolowski } 1095cd3d5c8SMarek Sokolowski 1105cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readString() { 1115cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::String)) 1125cd3d5c8SMarek Sokolowski return getExpectedError("string"); 1135cd3d5c8SMarek Sokolowski return read().value(); 1145cd3d5c8SMarek Sokolowski } 1155cd3d5c8SMarek Sokolowski 1165cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readIdentifier() { 1175cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Identifier)) 1185cd3d5c8SMarek Sokolowski return getExpectedError("identifier"); 1195cd3d5c8SMarek Sokolowski return read().value(); 1205cd3d5c8SMarek Sokolowski } 1215cd3d5c8SMarek Sokolowski 1227f110527SMarek Sokolowski Expected<IntOrString> RCParser::readIntOrString() { 1237f110527SMarek Sokolowski if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String)) 1247f110527SMarek Sokolowski return getExpectedError("int or string"); 1257f110527SMarek Sokolowski return IntOrString(read()); 1267f110527SMarek Sokolowski } 1277f110527SMarek Sokolowski 1285cd3d5c8SMarek Sokolowski Expected<IntOrString> RCParser::readTypeOrName() { 1295cd3d5c8SMarek Sokolowski // We suggest that the correct resource name or type should be either an 1305cd3d5c8SMarek Sokolowski // identifier or an integer. The original RC tool is much more liberal. 1315cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int)) 1325cd3d5c8SMarek Sokolowski return getExpectedError("int or identifier"); 1337f110527SMarek Sokolowski return IntOrString(read()); 1345cd3d5c8SMarek Sokolowski } 1355cd3d5c8SMarek Sokolowski 1365cd3d5c8SMarek Sokolowski Error RCParser::consumeType(Kind TokenKind) { 1375cd3d5c8SMarek Sokolowski if (isNextTokenKind(TokenKind)) { 1385cd3d5c8SMarek Sokolowski consume(); 1395cd3d5c8SMarek Sokolowski return Error::success(); 1405cd3d5c8SMarek Sokolowski } 1415cd3d5c8SMarek Sokolowski 1425cd3d5c8SMarek Sokolowski switch (TokenKind) { 1435cd3d5c8SMarek Sokolowski #define TOKEN(TokenName) \ 1445cd3d5c8SMarek Sokolowski case Kind::TokenName: \ 1455cd3d5c8SMarek Sokolowski return getExpectedError(#TokenName); 1465cd3d5c8SMarek Sokolowski #define SHORT_TOKEN(TokenName, TokenCh) \ 1475cd3d5c8SMarek Sokolowski case Kind::TokenName: \ 1485cd3d5c8SMarek Sokolowski return getExpectedError(#TokenCh); 1495cd3d5c8SMarek Sokolowski #include "ResourceScriptTokenList.h" 1505cd3d5c8SMarek Sokolowski #undef SHORT_TOKEN 1515cd3d5c8SMarek Sokolowski #undef TOKEN 1525cd3d5c8SMarek Sokolowski } 1535cd3d5c8SMarek Sokolowski 1545cd3d5c8SMarek Sokolowski llvm_unreachable("All case options exhausted."); 1555cd3d5c8SMarek Sokolowski } 1565cd3d5c8SMarek Sokolowski 1575cd3d5c8SMarek Sokolowski bool RCParser::consumeOptionalType(Kind TokenKind) { 1585cd3d5c8SMarek Sokolowski if (isNextTokenKind(TokenKind)) { 1595cd3d5c8SMarek Sokolowski consume(); 1605cd3d5c8SMarek Sokolowski return true; 1615cd3d5c8SMarek Sokolowski } 1625cd3d5c8SMarek Sokolowski 1635cd3d5c8SMarek Sokolowski return false; 1645cd3d5c8SMarek Sokolowski } 1655cd3d5c8SMarek Sokolowski 1665cd3d5c8SMarek Sokolowski Expected<SmallVector<uint32_t, 8>> 1675cd3d5c8SMarek Sokolowski RCParser::readIntsWithCommas(size_t MinCount, size_t MaxCount) { 1685cd3d5c8SMarek Sokolowski assert(MinCount <= MaxCount); 1695cd3d5c8SMarek Sokolowski 1705cd3d5c8SMarek Sokolowski SmallVector<uint32_t, 8> Result; 1715cd3d5c8SMarek Sokolowski 1725cd3d5c8SMarek Sokolowski auto FailureHandler = 1735cd3d5c8SMarek Sokolowski [&](llvm::Error Err) -> Expected<SmallVector<uint32_t, 8>> { 1745cd3d5c8SMarek Sokolowski if (Result.size() < MinCount) 1755cd3d5c8SMarek Sokolowski return std::move(Err); 1765cd3d5c8SMarek Sokolowski consumeError(std::move(Err)); 1775cd3d5c8SMarek Sokolowski return Result; 1785cd3d5c8SMarek Sokolowski }; 1795cd3d5c8SMarek Sokolowski 1805cd3d5c8SMarek Sokolowski for (size_t i = 0; i < MaxCount; ++i) { 1815cd3d5c8SMarek Sokolowski // Try to read a comma unless we read the first token. 1825cd3d5c8SMarek Sokolowski // Sometimes RC tool requires them and sometimes not. We decide to 1835cd3d5c8SMarek Sokolowski // always require them. 1845cd3d5c8SMarek Sokolowski if (i >= 1) { 1855cd3d5c8SMarek Sokolowski if (auto CommaError = consumeType(Kind::Comma)) 1865cd3d5c8SMarek Sokolowski return FailureHandler(std::move(CommaError)); 1875cd3d5c8SMarek Sokolowski } 1885cd3d5c8SMarek Sokolowski 1895cd3d5c8SMarek Sokolowski if (auto IntResult = readInt()) 1905cd3d5c8SMarek Sokolowski Result.push_back(*IntResult); 1915cd3d5c8SMarek Sokolowski else 1925cd3d5c8SMarek Sokolowski return FailureHandler(IntResult.takeError()); 1935cd3d5c8SMarek Sokolowski } 1945cd3d5c8SMarek Sokolowski 1955cd3d5c8SMarek Sokolowski return std::move(Result); 1965cd3d5c8SMarek Sokolowski } 1975cd3d5c8SMarek Sokolowski 1987f110527SMarek Sokolowski Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc) { 1997f110527SMarek Sokolowski assert(FlagDesc.size() <= 32 && "More than 32 flags won't fit in result."); 2007f110527SMarek Sokolowski assert(!FlagDesc.empty()); 2017f110527SMarek Sokolowski 2027f110527SMarek Sokolowski uint32_t Result = 0; 2037f110527SMarek Sokolowski while (isNextTokenKind(Kind::Comma)) { 2047f110527SMarek Sokolowski consume(); 2057f110527SMarek Sokolowski ASSIGN_OR_RETURN(FlagResult, readIdentifier()); 2067f110527SMarek Sokolowski bool FoundFlag = false; 2077f110527SMarek Sokolowski 2087f110527SMarek Sokolowski for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) { 2097f110527SMarek Sokolowski if (!FlagResult->equals_lower(FlagDesc[FlagId])) 2107f110527SMarek Sokolowski continue; 2117f110527SMarek Sokolowski 2127f110527SMarek Sokolowski Result |= (1U << FlagId); 2137f110527SMarek Sokolowski FoundFlag = true; 2147f110527SMarek Sokolowski break; 2157f110527SMarek Sokolowski } 2167f110527SMarek Sokolowski 2177f110527SMarek Sokolowski if (!FoundFlag) 2187f110527SMarek Sokolowski return getExpectedError(join(FlagDesc, "/"), true); 2197f110527SMarek Sokolowski } 2207f110527SMarek Sokolowski 2217f110527SMarek Sokolowski return Result; 2227f110527SMarek Sokolowski } 2237f110527SMarek Sokolowski 2245cd3d5c8SMarek Sokolowski // As for now, we ignore the extended set of statements. 2255cd3d5c8SMarek Sokolowski Expected<OptionalStmtList> RCParser::parseOptionalStatements(bool IsExtended) { 2265cd3d5c8SMarek Sokolowski OptionalStmtList Result; 2275cd3d5c8SMarek Sokolowski 2285cd3d5c8SMarek Sokolowski // The last statement is always followed by the start of the block. 2295cd3d5c8SMarek Sokolowski while (!isNextTokenKind(Kind::BlockBegin)) { 2305cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(IsExtended)); 2315cd3d5c8SMarek Sokolowski Result.addStmt(std::move(*SingleParse)); 2325cd3d5c8SMarek Sokolowski } 2335cd3d5c8SMarek Sokolowski 2345cd3d5c8SMarek Sokolowski return std::move(Result); 2355cd3d5c8SMarek Sokolowski } 2365cd3d5c8SMarek Sokolowski 2375cd3d5c8SMarek Sokolowski Expected<std::unique_ptr<OptionalStmt>> 2385cd3d5c8SMarek Sokolowski RCParser::parseSingleOptionalStatement(bool) { 2395cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(TypeToken, readIdentifier()); 2405cd3d5c8SMarek Sokolowski if (TypeToken->equals_lower("CHARACTERISTICS")) 2415cd3d5c8SMarek Sokolowski return parseCharacteristicsStmt(); 2425cd3d5c8SMarek Sokolowski else if (TypeToken->equals_lower("LANGUAGE")) 2435cd3d5c8SMarek Sokolowski return parseLanguageStmt(); 2445cd3d5c8SMarek Sokolowski else if (TypeToken->equals_lower("VERSION")) 2455cd3d5c8SMarek Sokolowski return parseVersionStmt(); 2465cd3d5c8SMarek Sokolowski else 2475cd3d5c8SMarek Sokolowski return getExpectedError("optional statement type, BEGIN or '{'", 2485cd3d5c8SMarek Sokolowski /* IsAlreadyRead = */ true); 2495cd3d5c8SMarek Sokolowski } 2505cd3d5c8SMarek Sokolowski 2515cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseLanguageResource() { 2525cd3d5c8SMarek Sokolowski // Read LANGUAGE as an optional statement. If it's read correctly, we can 2535cd3d5c8SMarek Sokolowski // upcast it to RCResource. 2545cd3d5c8SMarek Sokolowski return parseLanguageStmt(); 2555cd3d5c8SMarek Sokolowski } 2565cd3d5c8SMarek Sokolowski 2577f110527SMarek Sokolowski RCParser::ParseType RCParser::parseAcceleratorsResource() { 2587f110527SMarek Sokolowski ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); 2597f110527SMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); 2607f110527SMarek Sokolowski 2617f110527SMarek Sokolowski auto Accels = make_unique<AcceleratorsResource>(std::move(*OptStatements)); 2627f110527SMarek Sokolowski 2637f110527SMarek Sokolowski while (!consumeOptionalType(Kind::BlockEnd)) { 2647f110527SMarek Sokolowski ASSIGN_OR_RETURN(EventResult, readIntOrString()); 2657f110527SMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::Comma)); 2667f110527SMarek Sokolowski ASSIGN_OR_RETURN(IDResult, readInt()); 2677f110527SMarek Sokolowski ASSIGN_OR_RETURN(FlagsResult, 2687f110527SMarek Sokolowski parseFlags(AcceleratorsResource::Accelerator::OptionsStr)); 2697f110527SMarek Sokolowski Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult); 2707f110527SMarek Sokolowski } 2717f110527SMarek Sokolowski 2727f110527SMarek Sokolowski return std::move(Accels); 2737f110527SMarek Sokolowski } 2747f110527SMarek Sokolowski 27572aa937eSMarek Sokolowski RCParser::ParseType RCParser::parseCursorResource() { 27672aa937eSMarek Sokolowski ASSIGN_OR_RETURN(Arg, readString()); 27772aa937eSMarek Sokolowski return make_unique<CursorResource>(*Arg); 27872aa937eSMarek Sokolowski } 27972aa937eSMarek Sokolowski 2805cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseIconResource() { 2815cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readString()); 2825cd3d5c8SMarek Sokolowski return make_unique<IconResource>(*Arg); 2835cd3d5c8SMarek Sokolowski } 2845cd3d5c8SMarek Sokolowski 28572aa937eSMarek Sokolowski RCParser::ParseType RCParser::parseHTMLResource() { 28672aa937eSMarek Sokolowski ASSIGN_OR_RETURN(Arg, readString()); 28772aa937eSMarek Sokolowski return make_unique<HTMLResource>(*Arg); 28872aa937eSMarek Sokolowski } 28972aa937eSMarek Sokolowski 290*99ecb0ebSMarek Sokolowski RCParser::ParseType RCParser::parseMenuResource() { 291*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); 292*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(Items, parseMenuItemsList()); 293*99ecb0ebSMarek Sokolowski return make_unique<MenuResource>(std::move(*OptStatements), 294*99ecb0ebSMarek Sokolowski std::move(*Items)); 295*99ecb0ebSMarek Sokolowski } 296*99ecb0ebSMarek Sokolowski 297*99ecb0ebSMarek Sokolowski Expected<MenuDefinitionList> RCParser::parseMenuItemsList() { 298*99ecb0ebSMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); 299*99ecb0ebSMarek Sokolowski 300*99ecb0ebSMarek Sokolowski MenuDefinitionList List; 301*99ecb0ebSMarek Sokolowski 302*99ecb0ebSMarek Sokolowski // Read a set of items. Each item is of one of three kinds: 303*99ecb0ebSMarek Sokolowski // MENUITEM SEPARATOR 304*99ecb0ebSMarek Sokolowski // MENUITEM caption:String, result:Int [, menu flags]... 305*99ecb0ebSMarek Sokolowski // POPUP caption:String [, menu flags]... { items... } 306*99ecb0ebSMarek Sokolowski while (!consumeOptionalType(Kind::BlockEnd)) { 307*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier()); 308*99ecb0ebSMarek Sokolowski 309*99ecb0ebSMarek Sokolowski bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM"); 310*99ecb0ebSMarek Sokolowski bool IsPopup = ItemTypeResult->equals_lower("POPUP"); 311*99ecb0ebSMarek Sokolowski if (!IsMenuItem && !IsPopup) 312*99ecb0ebSMarek Sokolowski return getExpectedError("MENUITEM, POPUP, END or '}'", true); 313*99ecb0ebSMarek Sokolowski 314*99ecb0ebSMarek Sokolowski if (IsMenuItem && isNextTokenKind(Kind::Identifier)) { 315*99ecb0ebSMarek Sokolowski // Now, expecting SEPARATOR. 316*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(SeparatorResult, readIdentifier()); 317*99ecb0ebSMarek Sokolowski if (SeparatorResult->equals_lower("SEPARATOR")) { 318*99ecb0ebSMarek Sokolowski List.addDefinition(make_unique<MenuSeparator>()); 319*99ecb0ebSMarek Sokolowski continue; 320*99ecb0ebSMarek Sokolowski } 321*99ecb0ebSMarek Sokolowski 322*99ecb0ebSMarek Sokolowski return getExpectedError("SEPARATOR or string", true); 323*99ecb0ebSMarek Sokolowski } 324*99ecb0ebSMarek Sokolowski 325*99ecb0ebSMarek Sokolowski // Not a separator. Read the caption. 326*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(CaptionResult, readString()); 327*99ecb0ebSMarek Sokolowski 328*99ecb0ebSMarek Sokolowski // If MENUITEM, expect also a comma and an integer. 329*99ecb0ebSMarek Sokolowski uint32_t MenuResult = -1; 330*99ecb0ebSMarek Sokolowski 331*99ecb0ebSMarek Sokolowski if (IsMenuItem) { 332*99ecb0ebSMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::Comma)); 333*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(IntResult, readInt()); 334*99ecb0ebSMarek Sokolowski MenuResult = *IntResult; 335*99ecb0ebSMarek Sokolowski } 336*99ecb0ebSMarek Sokolowski 337*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr)); 338*99ecb0ebSMarek Sokolowski 339*99ecb0ebSMarek Sokolowski if (IsPopup) { 340*99ecb0ebSMarek Sokolowski // If POPUP, read submenu items recursively. 341*99ecb0ebSMarek Sokolowski ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList()); 342*99ecb0ebSMarek Sokolowski List.addDefinition(make_unique<PopupItem>(*CaptionResult, *FlagsResult, 343*99ecb0ebSMarek Sokolowski std::move(*SubMenuResult))); 344*99ecb0ebSMarek Sokolowski continue; 345*99ecb0ebSMarek Sokolowski } 346*99ecb0ebSMarek Sokolowski 347*99ecb0ebSMarek Sokolowski assert(IsMenuItem); 348*99ecb0ebSMarek Sokolowski List.addDefinition( 349*99ecb0ebSMarek Sokolowski make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult)); 350*99ecb0ebSMarek Sokolowski } 351*99ecb0ebSMarek Sokolowski 352*99ecb0ebSMarek Sokolowski return std::move(List); 353*99ecb0ebSMarek Sokolowski } 354*99ecb0ebSMarek Sokolowski 3555cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseStringTableResource() { 3565cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); 3575cd3d5c8SMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); 3585cd3d5c8SMarek Sokolowski 3595cd3d5c8SMarek Sokolowski auto Table = make_unique<StringTableResource>(std::move(*OptStatements)); 3605cd3d5c8SMarek Sokolowski 3615cd3d5c8SMarek Sokolowski // Read strings until we reach the end of the block. 3625cd3d5c8SMarek Sokolowski while (!consumeOptionalType(Kind::BlockEnd)) { 3635cd3d5c8SMarek Sokolowski // Each definition consists of string's ID (an integer) and a string. 3645cd3d5c8SMarek Sokolowski // Some examples in documentation suggest that there might be a comma in 3655cd3d5c8SMarek Sokolowski // between, however we strictly adhere to the single statement definition. 3665cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(IDResult, readInt()); 3675cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(StrResult, readString()); 3685cd3d5c8SMarek Sokolowski Table->addString(*IDResult, *StrResult); 3695cd3d5c8SMarek Sokolowski } 3705cd3d5c8SMarek Sokolowski 3715cd3d5c8SMarek Sokolowski return std::move(Table); 3725cd3d5c8SMarek Sokolowski } 3735cd3d5c8SMarek Sokolowski 3745cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseLanguageStmt() { 3755cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2)); 3765cd3d5c8SMarek Sokolowski return make_unique<LanguageResource>((*Args)[0], (*Args)[1]); 3775cd3d5c8SMarek Sokolowski } 3785cd3d5c8SMarek Sokolowski 3795cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() { 3805cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readInt()); 3815cd3d5c8SMarek Sokolowski return make_unique<CharacteristicsStmt>(*Arg); 3825cd3d5c8SMarek Sokolowski } 3835cd3d5c8SMarek Sokolowski 3845cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseVersionStmt() { 3855cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readInt()); 3865cd3d5c8SMarek Sokolowski return make_unique<VersionStmt>(*Arg); 3875cd3d5c8SMarek Sokolowski } 3885cd3d5c8SMarek Sokolowski 3895cd3d5c8SMarek Sokolowski Error RCParser::getExpectedError(const Twine Message, bool IsAlreadyRead) { 3905cd3d5c8SMarek Sokolowski return make_error<ParserError>( 3915cd3d5c8SMarek Sokolowski Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End); 3925cd3d5c8SMarek Sokolowski } 3935cd3d5c8SMarek Sokolowski 3945cd3d5c8SMarek Sokolowski } // namespace rc 3955cd3d5c8SMarek Sokolowski } // namespace llvm 396