1*c60b897dSRiver Riddle //===- LocationParser.cpp - MLIR Location Parser  -------------------------===//
2*c60b897dSRiver Riddle //
3*c60b897dSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c60b897dSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5*c60b897dSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c60b897dSRiver Riddle //
7*c60b897dSRiver Riddle //===----------------------------------------------------------------------===//
8*c60b897dSRiver Riddle 
9*c60b897dSRiver Riddle #include "Parser.h"
10*c60b897dSRiver Riddle 
11*c60b897dSRiver Riddle using namespace mlir;
12*c60b897dSRiver Riddle using namespace mlir::detail;
13*c60b897dSRiver Riddle 
14*c60b897dSRiver Riddle /// Specific location instances.
15*c60b897dSRiver Riddle ///
16*c60b897dSRiver Riddle /// location-inst ::= filelinecol-location |
17*c60b897dSRiver Riddle ///                   name-location |
18*c60b897dSRiver Riddle ///                   callsite-location |
19*c60b897dSRiver Riddle ///                   fused-location |
20*c60b897dSRiver Riddle ///                   unknown-location
21*c60b897dSRiver Riddle /// filelinecol-location ::= string-literal ':' integer-literal
22*c60b897dSRiver Riddle ///                                         ':' integer-literal
23*c60b897dSRiver Riddle /// name-location ::= string-literal
24*c60b897dSRiver Riddle /// callsite-location ::= 'callsite' '(' location-inst 'at' location-inst ')'
25*c60b897dSRiver Riddle /// fused-location ::= fused ('<' attribute-value '>')?
26*c60b897dSRiver Riddle ///                    '[' location-inst (location-inst ',')* ']'
27*c60b897dSRiver Riddle /// unknown-location ::= 'unknown'
28*c60b897dSRiver Riddle ///
parseCallSiteLocation(LocationAttr & loc)29*c60b897dSRiver Riddle ParseResult Parser::parseCallSiteLocation(LocationAttr &loc) {
30*c60b897dSRiver Riddle   consumeToken(Token::bare_identifier);
31*c60b897dSRiver Riddle 
32*c60b897dSRiver Riddle   // Parse the '('.
33*c60b897dSRiver Riddle   if (parseToken(Token::l_paren, "expected '(' in callsite location"))
34*c60b897dSRiver Riddle     return failure();
35*c60b897dSRiver Riddle 
36*c60b897dSRiver Riddle   // Parse the callee location.
37*c60b897dSRiver Riddle   LocationAttr calleeLoc;
38*c60b897dSRiver Riddle   if (parseLocationInstance(calleeLoc))
39*c60b897dSRiver Riddle     return failure();
40*c60b897dSRiver Riddle 
41*c60b897dSRiver Riddle   // Parse the 'at'.
42*c60b897dSRiver Riddle   if (getToken().isNot(Token::bare_identifier) ||
43*c60b897dSRiver Riddle       getToken().getSpelling() != "at")
44*c60b897dSRiver Riddle     return emitWrongTokenError("expected 'at' in callsite location");
45*c60b897dSRiver Riddle   consumeToken(Token::bare_identifier);
46*c60b897dSRiver Riddle 
47*c60b897dSRiver Riddle   // Parse the caller location.
48*c60b897dSRiver Riddle   LocationAttr callerLoc;
49*c60b897dSRiver Riddle   if (parseLocationInstance(callerLoc))
50*c60b897dSRiver Riddle     return failure();
51*c60b897dSRiver Riddle 
52*c60b897dSRiver Riddle   // Parse the ')'.
53*c60b897dSRiver Riddle   if (parseToken(Token::r_paren, "expected ')' in callsite location"))
54*c60b897dSRiver Riddle     return failure();
55*c60b897dSRiver Riddle 
56*c60b897dSRiver Riddle   // Return the callsite location.
57*c60b897dSRiver Riddle   loc = CallSiteLoc::get(calleeLoc, callerLoc);
58*c60b897dSRiver Riddle   return success();
59*c60b897dSRiver Riddle }
60*c60b897dSRiver Riddle 
parseFusedLocation(LocationAttr & loc)61*c60b897dSRiver Riddle ParseResult Parser::parseFusedLocation(LocationAttr &loc) {
62*c60b897dSRiver Riddle   consumeToken(Token::bare_identifier);
63*c60b897dSRiver Riddle 
64*c60b897dSRiver Riddle   // Try to parse the optional metadata.
65*c60b897dSRiver Riddle   Attribute metadata;
66*c60b897dSRiver Riddle   if (consumeIf(Token::less)) {
67*c60b897dSRiver Riddle     metadata = parseAttribute();
68*c60b897dSRiver Riddle     if (!metadata)
69*c60b897dSRiver Riddle       return failure();
70*c60b897dSRiver Riddle 
71*c60b897dSRiver Riddle     // Parse the '>' token.
72*c60b897dSRiver Riddle     if (parseToken(Token::greater,
73*c60b897dSRiver Riddle                    "expected '>' after fused location metadata"))
74*c60b897dSRiver Riddle       return failure();
75*c60b897dSRiver Riddle   }
76*c60b897dSRiver Riddle 
77*c60b897dSRiver Riddle   SmallVector<Location, 4> locations;
78*c60b897dSRiver Riddle   auto parseElt = [&] {
79*c60b897dSRiver Riddle     LocationAttr newLoc;
80*c60b897dSRiver Riddle     if (parseLocationInstance(newLoc))
81*c60b897dSRiver Riddle       return failure();
82*c60b897dSRiver Riddle     locations.push_back(newLoc);
83*c60b897dSRiver Riddle     return success();
84*c60b897dSRiver Riddle   };
85*c60b897dSRiver Riddle 
86*c60b897dSRiver Riddle   if (parseCommaSeparatedList(Delimiter::Square, parseElt,
87*c60b897dSRiver Riddle                               " in fused location"))
88*c60b897dSRiver Riddle     return failure();
89*c60b897dSRiver Riddle 
90*c60b897dSRiver Riddle   // Return the fused location.
91*c60b897dSRiver Riddle   loc = FusedLoc::get(locations, metadata, getContext());
92*c60b897dSRiver Riddle   return success();
93*c60b897dSRiver Riddle }
94*c60b897dSRiver Riddle 
parseNameOrFileLineColLocation(LocationAttr & loc)95*c60b897dSRiver Riddle ParseResult Parser::parseNameOrFileLineColLocation(LocationAttr &loc) {
96*c60b897dSRiver Riddle   auto *ctx = getContext();
97*c60b897dSRiver Riddle   auto str = getToken().getStringValue();
98*c60b897dSRiver Riddle   consumeToken(Token::string);
99*c60b897dSRiver Riddle 
100*c60b897dSRiver Riddle   // If the next token is ':' this is a filelinecol location.
101*c60b897dSRiver Riddle   if (consumeIf(Token::colon)) {
102*c60b897dSRiver Riddle     // Parse the line number.
103*c60b897dSRiver Riddle     if (getToken().isNot(Token::integer))
104*c60b897dSRiver Riddle       return emitWrongTokenError(
105*c60b897dSRiver Riddle           "expected integer line number in FileLineColLoc");
106*c60b897dSRiver Riddle     auto line = getToken().getUnsignedIntegerValue();
107*c60b897dSRiver Riddle     if (!line)
108*c60b897dSRiver Riddle       return emitWrongTokenError(
109*c60b897dSRiver Riddle           "expected integer line number in FileLineColLoc");
110*c60b897dSRiver Riddle     consumeToken(Token::integer);
111*c60b897dSRiver Riddle 
112*c60b897dSRiver Riddle     // Parse the ':'.
113*c60b897dSRiver Riddle     if (parseToken(Token::colon, "expected ':' in FileLineColLoc"))
114*c60b897dSRiver Riddle       return failure();
115*c60b897dSRiver Riddle 
116*c60b897dSRiver Riddle     // Parse the column number.
117*c60b897dSRiver Riddle     if (getToken().isNot(Token::integer))
118*c60b897dSRiver Riddle       return emitWrongTokenError(
119*c60b897dSRiver Riddle           "expected integer column number in FileLineColLoc");
120*c60b897dSRiver Riddle     auto column = getToken().getUnsignedIntegerValue();
121*c60b897dSRiver Riddle     if (!column.has_value())
122*c60b897dSRiver Riddle       return emitError("expected integer column number in FileLineColLoc");
123*c60b897dSRiver Riddle     consumeToken(Token::integer);
124*c60b897dSRiver Riddle 
125*c60b897dSRiver Riddle     loc = FileLineColLoc::get(ctx, str, line.value(), column.value());
126*c60b897dSRiver Riddle     return success();
127*c60b897dSRiver Riddle   }
128*c60b897dSRiver Riddle 
129*c60b897dSRiver Riddle   // Otherwise, this is a NameLoc.
130*c60b897dSRiver Riddle 
131*c60b897dSRiver Riddle   // Check for a child location.
132*c60b897dSRiver Riddle   if (consumeIf(Token::l_paren)) {
133*c60b897dSRiver Riddle     // Parse the child location.
134*c60b897dSRiver Riddle     LocationAttr childLoc;
135*c60b897dSRiver Riddle     if (parseLocationInstance(childLoc))
136*c60b897dSRiver Riddle       return failure();
137*c60b897dSRiver Riddle 
138*c60b897dSRiver Riddle     loc = NameLoc::get(StringAttr::get(ctx, str), childLoc);
139*c60b897dSRiver Riddle 
140*c60b897dSRiver Riddle     // Parse the closing ')'.
141*c60b897dSRiver Riddle     if (parseToken(Token::r_paren,
142*c60b897dSRiver Riddle                    "expected ')' after child location of NameLoc"))
143*c60b897dSRiver Riddle       return failure();
144*c60b897dSRiver Riddle   } else {
145*c60b897dSRiver Riddle     loc = NameLoc::get(StringAttr::get(ctx, str));
146*c60b897dSRiver Riddle   }
147*c60b897dSRiver Riddle 
148*c60b897dSRiver Riddle   return success();
149*c60b897dSRiver Riddle }
150*c60b897dSRiver Riddle 
parseLocationInstance(LocationAttr & loc)151*c60b897dSRiver Riddle ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
152*c60b897dSRiver Riddle   // Handle either name or filelinecol locations.
153*c60b897dSRiver Riddle   if (getToken().is(Token::string))
154*c60b897dSRiver Riddle     return parseNameOrFileLineColLocation(loc);
155*c60b897dSRiver Riddle 
156*c60b897dSRiver Riddle   // Bare tokens required for other cases.
157*c60b897dSRiver Riddle   if (!getToken().is(Token::bare_identifier))
158*c60b897dSRiver Riddle     return emitWrongTokenError("expected location instance");
159*c60b897dSRiver Riddle 
160*c60b897dSRiver Riddle   // Check for the 'callsite' signifying a callsite location.
161*c60b897dSRiver Riddle   if (getToken().getSpelling() == "callsite")
162*c60b897dSRiver Riddle     return parseCallSiteLocation(loc);
163*c60b897dSRiver Riddle 
164*c60b897dSRiver Riddle   // If the token is 'fused', then this is a fused location.
165*c60b897dSRiver Riddle   if (getToken().getSpelling() == "fused")
166*c60b897dSRiver Riddle     return parseFusedLocation(loc);
167*c60b897dSRiver Riddle 
168*c60b897dSRiver Riddle   // Check for a 'unknown' for an unknown location.
169*c60b897dSRiver Riddle   if (getToken().getSpelling() == "unknown") {
170*c60b897dSRiver Riddle     consumeToken(Token::bare_identifier);
171*c60b897dSRiver Riddle     loc = UnknownLoc::get(getContext());
172*c60b897dSRiver Riddle     return success();
173*c60b897dSRiver Riddle   }
174*c60b897dSRiver Riddle 
175*c60b897dSRiver Riddle   return emitWrongTokenError("expected location instance");
176*c60b897dSRiver Riddle }
177