1*5cd3d5c8SMarek Sokolowski //===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===//
2*5cd3d5c8SMarek Sokolowski //
3*5cd3d5c8SMarek Sokolowski //                     The LLVM Compiler Infrastructure
4*5cd3d5c8SMarek Sokolowski //
5*5cd3d5c8SMarek Sokolowski // This file is distributed under the University of Illinois Open Source
6*5cd3d5c8SMarek Sokolowski // License. See LICENSE.TXT for details.
7*5cd3d5c8SMarek Sokolowski //
8*5cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===//
9*5cd3d5c8SMarek Sokolowski //
10*5cd3d5c8SMarek Sokolowski // This implements the parser defined in ResourceScriptParser.h.
11*5cd3d5c8SMarek Sokolowski //
12*5cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===//
13*5cd3d5c8SMarek Sokolowski 
14*5cd3d5c8SMarek Sokolowski #include "ResourceScriptParser.h"
15*5cd3d5c8SMarek Sokolowski 
16*5cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Error and forward the error if it exists.
17*5cd3d5c8SMarek Sokolowski #define RETURN_IF_ERROR(Expr)                                                  \
18*5cd3d5c8SMarek Sokolowski   if (auto Err = (Expr))                                                       \
19*5cd3d5c8SMarek Sokolowski     return std::move(Err);
20*5cd3d5c8SMarek Sokolowski 
21*5cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Expected<T> and assign it to Var or
22*5cd3d5c8SMarek Sokolowski // forward the error out of the function.
23*5cd3d5c8SMarek Sokolowski #define ASSIGN_OR_RETURN(Var, Expr)                                            \
24*5cd3d5c8SMarek Sokolowski   auto Var = (Expr);                                                           \
25*5cd3d5c8SMarek Sokolowski   if (!Var)                                                                    \
26*5cd3d5c8SMarek Sokolowski     return Var.takeError();
27*5cd3d5c8SMarek Sokolowski 
28*5cd3d5c8SMarek Sokolowski namespace llvm {
29*5cd3d5c8SMarek Sokolowski namespace rc {
30*5cd3d5c8SMarek Sokolowski 
31*5cd3d5c8SMarek Sokolowski RCParser::ParserError::ParserError(const Twine Expected, const LocIter CurLoc,
32*5cd3d5c8SMarek Sokolowski                                    const LocIter End)
33*5cd3d5c8SMarek Sokolowski     : ErrorLoc(CurLoc), FileEnd(End) {
34*5cd3d5c8SMarek Sokolowski   CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
35*5cd3d5c8SMarek Sokolowski                (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
36*5cd3d5c8SMarek Sokolowski }
37*5cd3d5c8SMarek Sokolowski 
38*5cd3d5c8SMarek Sokolowski char RCParser::ParserError::ID = 0;
39*5cd3d5c8SMarek Sokolowski 
40*5cd3d5c8SMarek Sokolowski RCParser::RCParser(const std::vector<RCToken> &TokenList)
41*5cd3d5c8SMarek Sokolowski     : Tokens(TokenList), CurLoc(Tokens.begin()), End(Tokens.end()) {}
42*5cd3d5c8SMarek Sokolowski 
43*5cd3d5c8SMarek Sokolowski RCParser::RCParser(std::vector<RCToken> &&TokenList)
44*5cd3d5c8SMarek Sokolowski     : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
45*5cd3d5c8SMarek Sokolowski 
46*5cd3d5c8SMarek Sokolowski bool RCParser::isEof() const { return CurLoc == End; }
47*5cd3d5c8SMarek Sokolowski 
48*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseSingleResource() {
49*5cd3d5c8SMarek Sokolowski   // The first thing we read is usually a resource's name. However, in some
50*5cd3d5c8SMarek Sokolowski   // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
51*5cd3d5c8SMarek Sokolowski   // and the first token to be read is the type.
52*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(NameToken, readTypeOrName());
53*5cd3d5c8SMarek Sokolowski 
54*5cd3d5c8SMarek Sokolowski   if (NameToken->equalsLower("LANGUAGE"))
55*5cd3d5c8SMarek Sokolowski     return parseLanguageResource();
56*5cd3d5c8SMarek Sokolowski   else if (NameToken->equalsLower("STRINGTABLE"))
57*5cd3d5c8SMarek Sokolowski     return parseStringTableResource();
58*5cd3d5c8SMarek Sokolowski 
59*5cd3d5c8SMarek Sokolowski   // If it's not an unnamed resource, what we've just read is a name. Now,
60*5cd3d5c8SMarek Sokolowski   // read resource type;
61*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
62*5cd3d5c8SMarek Sokolowski 
63*5cd3d5c8SMarek Sokolowski   ParseType Result = std::unique_ptr<RCResource>();
64*5cd3d5c8SMarek Sokolowski   (void)!Result;
65*5cd3d5c8SMarek Sokolowski 
66*5cd3d5c8SMarek Sokolowski   if (TypeToken->equalsLower("ICON"))
67*5cd3d5c8SMarek Sokolowski     Result = parseIconResource();
68*5cd3d5c8SMarek Sokolowski   else
69*5cd3d5c8SMarek Sokolowski     return getExpectedError("resource type", /* IsAlreadyRead = */ true);
70*5cd3d5c8SMarek Sokolowski 
71*5cd3d5c8SMarek Sokolowski   if (Result)
72*5cd3d5c8SMarek Sokolowski     (*Result)->setName(*NameToken);
73*5cd3d5c8SMarek Sokolowski 
74*5cd3d5c8SMarek Sokolowski   return Result;
75*5cd3d5c8SMarek Sokolowski }
76*5cd3d5c8SMarek Sokolowski 
77*5cd3d5c8SMarek Sokolowski bool RCParser::isNextTokenKind(Kind TokenKind) const {
78*5cd3d5c8SMarek Sokolowski   return !isEof() && look().kind() == TokenKind;
79*5cd3d5c8SMarek Sokolowski }
80*5cd3d5c8SMarek Sokolowski 
81*5cd3d5c8SMarek Sokolowski const RCToken &RCParser::look() const {
82*5cd3d5c8SMarek Sokolowski   assert(!isEof());
83*5cd3d5c8SMarek Sokolowski   return *CurLoc;
84*5cd3d5c8SMarek Sokolowski }
85*5cd3d5c8SMarek Sokolowski 
86*5cd3d5c8SMarek Sokolowski const RCToken &RCParser::read() {
87*5cd3d5c8SMarek Sokolowski   assert(!isEof());
88*5cd3d5c8SMarek Sokolowski   return *CurLoc++;
89*5cd3d5c8SMarek Sokolowski }
90*5cd3d5c8SMarek Sokolowski 
91*5cd3d5c8SMarek Sokolowski void RCParser::consume() {
92*5cd3d5c8SMarek Sokolowski   assert(!isEof());
93*5cd3d5c8SMarek Sokolowski   CurLoc++;
94*5cd3d5c8SMarek Sokolowski }
95*5cd3d5c8SMarek Sokolowski 
96*5cd3d5c8SMarek Sokolowski Expected<uint32_t> RCParser::readInt() {
97*5cd3d5c8SMarek Sokolowski   if (!isNextTokenKind(Kind::Int))
98*5cd3d5c8SMarek Sokolowski     return getExpectedError("integer");
99*5cd3d5c8SMarek Sokolowski   return read().intValue();
100*5cd3d5c8SMarek Sokolowski }
101*5cd3d5c8SMarek Sokolowski 
102*5cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readString() {
103*5cd3d5c8SMarek Sokolowski   if (!isNextTokenKind(Kind::String))
104*5cd3d5c8SMarek Sokolowski     return getExpectedError("string");
105*5cd3d5c8SMarek Sokolowski   return read().value();
106*5cd3d5c8SMarek Sokolowski }
107*5cd3d5c8SMarek Sokolowski 
108*5cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readIdentifier() {
109*5cd3d5c8SMarek Sokolowski   if (!isNextTokenKind(Kind::Identifier))
110*5cd3d5c8SMarek Sokolowski     return getExpectedError("identifier");
111*5cd3d5c8SMarek Sokolowski   return read().value();
112*5cd3d5c8SMarek Sokolowski }
113*5cd3d5c8SMarek Sokolowski 
114*5cd3d5c8SMarek Sokolowski Expected<IntOrString> RCParser::readTypeOrName() {
115*5cd3d5c8SMarek Sokolowski   // We suggest that the correct resource name or type should be either an
116*5cd3d5c8SMarek Sokolowski   // identifier or an integer. The original RC tool is much more liberal.
117*5cd3d5c8SMarek Sokolowski   if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
118*5cd3d5c8SMarek Sokolowski     return getExpectedError("int or identifier");
119*5cd3d5c8SMarek Sokolowski 
120*5cd3d5c8SMarek Sokolowski   const RCToken &Tok = read();
121*5cd3d5c8SMarek Sokolowski   if (Tok.kind() == Kind::Int)
122*5cd3d5c8SMarek Sokolowski     return IntOrString(Tok.intValue());
123*5cd3d5c8SMarek Sokolowski   else
124*5cd3d5c8SMarek Sokolowski     return IntOrString(Tok.value());
125*5cd3d5c8SMarek Sokolowski }
126*5cd3d5c8SMarek Sokolowski 
127*5cd3d5c8SMarek Sokolowski Error RCParser::consumeType(Kind TokenKind) {
128*5cd3d5c8SMarek Sokolowski   if (isNextTokenKind(TokenKind)) {
129*5cd3d5c8SMarek Sokolowski     consume();
130*5cd3d5c8SMarek Sokolowski     return Error::success();
131*5cd3d5c8SMarek Sokolowski   }
132*5cd3d5c8SMarek Sokolowski 
133*5cd3d5c8SMarek Sokolowski   switch (TokenKind) {
134*5cd3d5c8SMarek Sokolowski #define TOKEN(TokenName)                                                       \
135*5cd3d5c8SMarek Sokolowski   case Kind::TokenName:                                                        \
136*5cd3d5c8SMarek Sokolowski     return getExpectedError(#TokenName);
137*5cd3d5c8SMarek Sokolowski #define SHORT_TOKEN(TokenName, TokenCh)                                        \
138*5cd3d5c8SMarek Sokolowski   case Kind::TokenName:                                                        \
139*5cd3d5c8SMarek Sokolowski     return getExpectedError(#TokenCh);
140*5cd3d5c8SMarek Sokolowski #include "ResourceScriptTokenList.h"
141*5cd3d5c8SMarek Sokolowski #undef SHORT_TOKEN
142*5cd3d5c8SMarek Sokolowski #undef TOKEN
143*5cd3d5c8SMarek Sokolowski   }
144*5cd3d5c8SMarek Sokolowski 
145*5cd3d5c8SMarek Sokolowski   llvm_unreachable("All case options exhausted.");
146*5cd3d5c8SMarek Sokolowski }
147*5cd3d5c8SMarek Sokolowski 
148*5cd3d5c8SMarek Sokolowski bool RCParser::consumeOptionalType(Kind TokenKind) {
149*5cd3d5c8SMarek Sokolowski   if (isNextTokenKind(TokenKind)) {
150*5cd3d5c8SMarek Sokolowski     consume();
151*5cd3d5c8SMarek Sokolowski     return true;
152*5cd3d5c8SMarek Sokolowski   }
153*5cd3d5c8SMarek Sokolowski 
154*5cd3d5c8SMarek Sokolowski   return false;
155*5cd3d5c8SMarek Sokolowski }
156*5cd3d5c8SMarek Sokolowski 
157*5cd3d5c8SMarek Sokolowski Expected<SmallVector<uint32_t, 8>>
158*5cd3d5c8SMarek Sokolowski RCParser::readIntsWithCommas(size_t MinCount, size_t MaxCount) {
159*5cd3d5c8SMarek Sokolowski   assert(MinCount <= MaxCount);
160*5cd3d5c8SMarek Sokolowski 
161*5cd3d5c8SMarek Sokolowski   SmallVector<uint32_t, 8> Result;
162*5cd3d5c8SMarek Sokolowski 
163*5cd3d5c8SMarek Sokolowski   auto FailureHandler =
164*5cd3d5c8SMarek Sokolowski       [&](llvm::Error Err) -> Expected<SmallVector<uint32_t, 8>> {
165*5cd3d5c8SMarek Sokolowski     if (Result.size() < MinCount)
166*5cd3d5c8SMarek Sokolowski       return std::move(Err);
167*5cd3d5c8SMarek Sokolowski     consumeError(std::move(Err));
168*5cd3d5c8SMarek Sokolowski     return Result;
169*5cd3d5c8SMarek Sokolowski   };
170*5cd3d5c8SMarek Sokolowski 
171*5cd3d5c8SMarek Sokolowski   for (size_t i = 0; i < MaxCount; ++i) {
172*5cd3d5c8SMarek Sokolowski     // Try to read a comma unless we read the first token.
173*5cd3d5c8SMarek Sokolowski     // Sometimes RC tool requires them and sometimes not. We decide to
174*5cd3d5c8SMarek Sokolowski     // always require them.
175*5cd3d5c8SMarek Sokolowski     if (i >= 1) {
176*5cd3d5c8SMarek Sokolowski       if (auto CommaError = consumeType(Kind::Comma))
177*5cd3d5c8SMarek Sokolowski         return FailureHandler(std::move(CommaError));
178*5cd3d5c8SMarek Sokolowski     }
179*5cd3d5c8SMarek Sokolowski 
180*5cd3d5c8SMarek Sokolowski     if (auto IntResult = readInt())
181*5cd3d5c8SMarek Sokolowski       Result.push_back(*IntResult);
182*5cd3d5c8SMarek Sokolowski     else
183*5cd3d5c8SMarek Sokolowski       return FailureHandler(IntResult.takeError());
184*5cd3d5c8SMarek Sokolowski   }
185*5cd3d5c8SMarek Sokolowski 
186*5cd3d5c8SMarek Sokolowski   return std::move(Result);
187*5cd3d5c8SMarek Sokolowski }
188*5cd3d5c8SMarek Sokolowski 
189*5cd3d5c8SMarek Sokolowski // As for now, we ignore the extended set of statements.
190*5cd3d5c8SMarek Sokolowski Expected<OptionalStmtList> RCParser::parseOptionalStatements(bool IsExtended) {
191*5cd3d5c8SMarek Sokolowski   OptionalStmtList Result;
192*5cd3d5c8SMarek Sokolowski 
193*5cd3d5c8SMarek Sokolowski   // The last statement is always followed by the start of the block.
194*5cd3d5c8SMarek Sokolowski   while (!isNextTokenKind(Kind::BlockBegin)) {
195*5cd3d5c8SMarek Sokolowski     ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(IsExtended));
196*5cd3d5c8SMarek Sokolowski     Result.addStmt(std::move(*SingleParse));
197*5cd3d5c8SMarek Sokolowski   }
198*5cd3d5c8SMarek Sokolowski 
199*5cd3d5c8SMarek Sokolowski   return std::move(Result);
200*5cd3d5c8SMarek Sokolowski }
201*5cd3d5c8SMarek Sokolowski 
202*5cd3d5c8SMarek Sokolowski Expected<std::unique_ptr<OptionalStmt>>
203*5cd3d5c8SMarek Sokolowski RCParser::parseSingleOptionalStatement(bool) {
204*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(TypeToken, readIdentifier());
205*5cd3d5c8SMarek Sokolowski   if (TypeToken->equals_lower("CHARACTERISTICS"))
206*5cd3d5c8SMarek Sokolowski     return parseCharacteristicsStmt();
207*5cd3d5c8SMarek Sokolowski   else if (TypeToken->equals_lower("LANGUAGE"))
208*5cd3d5c8SMarek Sokolowski     return parseLanguageStmt();
209*5cd3d5c8SMarek Sokolowski   else if (TypeToken->equals_lower("VERSION"))
210*5cd3d5c8SMarek Sokolowski     return parseVersionStmt();
211*5cd3d5c8SMarek Sokolowski   else
212*5cd3d5c8SMarek Sokolowski     return getExpectedError("optional statement type, BEGIN or '{'",
213*5cd3d5c8SMarek Sokolowski                             /* IsAlreadyRead = */ true);
214*5cd3d5c8SMarek Sokolowski }
215*5cd3d5c8SMarek Sokolowski 
216*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseLanguageResource() {
217*5cd3d5c8SMarek Sokolowski   // Read LANGUAGE as an optional statement. If it's read correctly, we can
218*5cd3d5c8SMarek Sokolowski   // upcast it to RCResource.
219*5cd3d5c8SMarek Sokolowski   return parseLanguageStmt();
220*5cd3d5c8SMarek Sokolowski }
221*5cd3d5c8SMarek Sokolowski 
222*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseIconResource() {
223*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(Arg, readString());
224*5cd3d5c8SMarek Sokolowski   return make_unique<IconResource>(*Arg);
225*5cd3d5c8SMarek Sokolowski }
226*5cd3d5c8SMarek Sokolowski 
227*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseStringTableResource() {
228*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
229*5cd3d5c8SMarek Sokolowski   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
230*5cd3d5c8SMarek Sokolowski 
231*5cd3d5c8SMarek Sokolowski   auto Table = make_unique<StringTableResource>(std::move(*OptStatements));
232*5cd3d5c8SMarek Sokolowski 
233*5cd3d5c8SMarek Sokolowski   // Read strings until we reach the end of the block.
234*5cd3d5c8SMarek Sokolowski   while (!consumeOptionalType(Kind::BlockEnd)) {
235*5cd3d5c8SMarek Sokolowski     // Each definition consists of string's ID (an integer) and a string.
236*5cd3d5c8SMarek Sokolowski     // Some examples in documentation suggest that there might be a comma in
237*5cd3d5c8SMarek Sokolowski     // between, however we strictly adhere to the single statement definition.
238*5cd3d5c8SMarek Sokolowski     ASSIGN_OR_RETURN(IDResult, readInt());
239*5cd3d5c8SMarek Sokolowski     ASSIGN_OR_RETURN(StrResult, readString());
240*5cd3d5c8SMarek Sokolowski     Table->addString(*IDResult, *StrResult);
241*5cd3d5c8SMarek Sokolowski   }
242*5cd3d5c8SMarek Sokolowski 
243*5cd3d5c8SMarek Sokolowski   return std::move(Table);
244*5cd3d5c8SMarek Sokolowski }
245*5cd3d5c8SMarek Sokolowski 
246*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseLanguageStmt() {
247*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
248*5cd3d5c8SMarek Sokolowski   return make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
249*5cd3d5c8SMarek Sokolowski }
250*5cd3d5c8SMarek Sokolowski 
251*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
252*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(Arg, readInt());
253*5cd3d5c8SMarek Sokolowski   return make_unique<CharacteristicsStmt>(*Arg);
254*5cd3d5c8SMarek Sokolowski }
255*5cd3d5c8SMarek Sokolowski 
256*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseVersionStmt() {
257*5cd3d5c8SMarek Sokolowski   ASSIGN_OR_RETURN(Arg, readInt());
258*5cd3d5c8SMarek Sokolowski   return make_unique<VersionStmt>(*Arg);
259*5cd3d5c8SMarek Sokolowski }
260*5cd3d5c8SMarek Sokolowski 
261*5cd3d5c8SMarek Sokolowski Error RCParser::getExpectedError(const Twine Message, bool IsAlreadyRead) {
262*5cd3d5c8SMarek Sokolowski   return make_error<ParserError>(
263*5cd3d5c8SMarek Sokolowski       Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
264*5cd3d5c8SMarek Sokolowski }
265*5cd3d5c8SMarek Sokolowski 
266*5cd3d5c8SMarek Sokolowski } // namespace rc
267*5cd3d5c8SMarek Sokolowski } // namespace llvm
268