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