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#include "Token.h"
11#include "mlir/IR/Attributes.h"
12#include "mlir/IR/BuiltinAttributes.h"
13#include "mlir/IR/Location.h"
14#include "mlir/Support/LLVM.h"
15#include <optional>
16
17using namespace mlir;
18using namespace mlir::detail;
19
20/// Specific location instances.
21///
22/// location-inst ::= filelinecol-location |
23/// name-location |
24/// callsite-location |
25/// fused-location |
26/// unknown-location
27/// filelinecol-location ::= string-literal ':' integer-literal
28/// ':' integer-literal
29/// name-location ::= string-literal
30/// callsite-location ::= 'callsite' '(' location-inst 'at' location-inst ')'
31/// fused-location ::= fused ('<' attribute-value '>')?
32/// '[' location-inst (location-inst ',')* ']'
33/// unknown-location ::= 'unknown'
34///
35ParseResult Parser::parseCallSiteLocation(LocationAttr &loc) {
36 consumeToken(kind: Token::bare_identifier);
37
38 // Parse the '('.
39 if (parseToken(expectedToken: Token::l_paren, message: "expected '(' in callsite location"))
40 return failure();
41
42 // Parse the callee location.
43 LocationAttr calleeLoc;
44 if (parseLocationInstance(loc&: calleeLoc))
45 return failure();
46
47 // Parse the 'at'.
48 if (getToken().isNot(k: Token::bare_identifier) ||
49 getToken().getSpelling() != "at")
50 return emitWrongTokenError(message: "expected 'at' in callsite location");
51 consumeToken(kind: Token::bare_identifier);
52
53 // Parse the caller location.
54 LocationAttr callerLoc;
55 if (parseLocationInstance(loc&: callerLoc))
56 return failure();
57
58 // Parse the ')'.
59 if (parseToken(expectedToken: Token::r_paren, message: "expected ')' in callsite location"))
60 return failure();
61
62 // Return the callsite location.
63 loc = CallSiteLoc::get(calleeLoc, callerLoc);
64 return success();
65}
66
67ParseResult Parser::parseFusedLocation(LocationAttr &loc) {
68 consumeToken(kind: Token::bare_identifier);
69
70 // Try to parse the optional metadata.
71 Attribute metadata;
72 if (consumeIf(kind: Token::less)) {
73 metadata = parseAttribute();
74 if (!metadata)
75 return failure();
76
77 // Parse the '>' token.
78 if (parseToken(expectedToken: Token::greater,
79 message: "expected '>' after fused location metadata"))
80 return failure();
81 }
82
83 SmallVector<Location, 4> locations;
84 auto parseElt = [&] {
85 LocationAttr newLoc;
86 if (parseLocationInstance(loc&: newLoc))
87 return failure();
88 locations.push_back(Elt: newLoc);
89 return success();
90 };
91
92 if (parseCommaSeparatedList(delimiter: Delimiter::Square, parseElementFn: parseElt,
93 contextMessage: " in fused location"))
94 return failure();
95
96 // Return the fused location.
97 loc = FusedLoc::get(locations, metadata, getContext());
98 return success();
99}
100
101ParseResult Parser::parseNameOrFileLineColRange(LocationAttr &loc) {
102 auto *ctx = getContext();
103 auto str = getToken().getStringValue();
104 consumeToken(kind: Token::string);
105
106 std::optional<unsigned> startLine, startColumn, endLine, endColumn;
107
108 // If the next token is ':' this is a filelinecol location.
109 if (consumeIf(kind: Token::colon)) {
110 // Parse the line number.
111 if (getToken().isNot(k: Token::integer))
112 return emitWrongTokenError(
113 message: "expected integer line number in FileLineColRange");
114 startLine = getToken().getUnsignedIntegerValue();
115 if (!startLine)
116 return emitWrongTokenError(
117 message: "expected integer line number in FileLineColRange");
118 consumeToken(kind: Token::integer);
119
120 // Parse the ':'.
121 if (getToken().isNot(k: Token::colon)) {
122 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine);
123 return success();
124 }
125 consumeToken(kind: Token::colon);
126
127 // Parse the column number.
128 if (getToken().isNot(k: Token::integer)) {
129 return emitWrongTokenError(
130 message: "expected integer column number in FileLineColRange");
131 }
132 startColumn = getToken().getUnsignedIntegerValue();
133 if (!startColumn.has_value())
134 return emitError(message: "expected integer column number in FileLineColRange");
135 consumeToken(kind: Token::integer);
136
137 if (!isCurrentTokenAKeyword() || getTokenSpelling() != "to") {
138 loc = FileLineColLoc::get(context: ctx, fileName: str, line: *startLine, column: *startColumn);
139 return success();
140 }
141 consumeToken();
142
143 // Parse the line number.
144 if (getToken().is(k: Token::integer)) {
145 endLine = getToken().getUnsignedIntegerValue();
146 if (!endLine) {
147 return emitWrongTokenError(
148 message: "expected integer line number in FileLineColRange");
149 }
150 consumeToken(kind: Token::integer);
151 }
152
153 // Parse the ':'.
154 if (getToken().isNot(k: Token::colon)) {
155 return emitWrongTokenError(
156 message: "expected either integer or `:` post `to` in FileLineColRange");
157 }
158 consumeToken(kind: Token::colon);
159
160 // Parse the column number.
161 if (getToken().isNot(k: Token::integer)) {
162 return emitWrongTokenError(
163 message: "expected integer column number in FileLineColRange");
164 }
165 endColumn = getToken().getUnsignedIntegerValue();
166 if (!endColumn.has_value())
167 return emitError(message: "expected integer column number in FileLineColRange");
168 consumeToken(kind: Token::integer);
169
170 if (endLine.has_value()) {
171 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine,
172 *startColumn, *endLine, *endColumn);
173 } else {
174 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine,
175 *startColumn, *endColumn);
176 }
177 return success();
178 }
179
180 // Otherwise, this is a NameLoc.
181
182 // Check for a child location.
183 if (consumeIf(kind: Token::l_paren)) {
184 // Parse the child location.
185 LocationAttr childLoc;
186 if (parseLocationInstance(loc&: childLoc))
187 return failure();
188
189 loc = NameLoc::get(StringAttr::get(ctx, str), childLoc);
190
191 // Parse the closing ')'.
192 if (parseToken(expectedToken: Token::r_paren,
193 message: "expected ')' after child location of NameLoc"))
194 return failure();
195 } else {
196 loc = NameLoc::get(StringAttr::get(ctx, str));
197 }
198
199 return success();
200}
201
202ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
203 // Handle aliases.
204 if (getToken().is(k: Token::hash_identifier)) {
205 Attribute locAttr = parseExtendedAttr(type: Type());
206 if (!locAttr)
207 return failure();
208 if (!(loc = dyn_cast<LocationAttr>(Val&: locAttr)))
209 return emitError(message: "expected location attribute, but got") << locAttr;
210 return success();
211 }
212
213 // Handle either name or filelinecol locations.
214 if (getToken().is(k: Token::string))
215 return parseNameOrFileLineColRange(loc);
216
217 // Bare tokens required for other cases.
218 if (!getToken().is(k: Token::bare_identifier))
219 return emitWrongTokenError(message: "expected location instance");
220
221 // Check for the 'callsite' signifying a callsite location.
222 if (getToken().getSpelling() == "callsite")
223 return parseCallSiteLocation(loc);
224
225 // If the token is 'fused', then this is a fused location.
226 if (getToken().getSpelling() == "fused")
227 return parseFusedLocation(loc);
228
229 // Check for a 'unknown' for an unknown location.
230 if (getToken().getSpelling() == "unknown") {
231 consumeToken(kind: Token::bare_identifier);
232 loc = UnknownLoc::get(getContext());
233 return success();
234 }
235
236 return emitWrongTokenError(message: "expected location instance");
237}
238

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of mlir/lib/AsmParser/LocationParser.cpp