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 "mlir/Support/LogicalResult.h"
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::parseNameOrFileLineColLocation(LocationAttr &loc) {
102 auto *ctx = getContext();
103 auto str = getToken().getStringValue();
104 consumeToken(kind: Token::string);
105
106 // If the next token is ':' this is a filelinecol location.
107 if (consumeIf(kind: Token::colon)) {
108 // Parse the line number.
109 if (getToken().isNot(k: Token::integer))
110 return emitWrongTokenError(
111 message: "expected integer line number in FileLineColLoc");
112 auto line = getToken().getUnsignedIntegerValue();
113 if (!line)
114 return emitWrongTokenError(
115 message: "expected integer line number in FileLineColLoc");
116 consumeToken(kind: Token::integer);
117
118 // Parse the ':'.
119 if (parseToken(expectedToken: Token::colon, message: "expected ':' in FileLineColLoc"))
120 return failure();
121
122 // Parse the column number.
123 if (getToken().isNot(k: Token::integer))
124 return emitWrongTokenError(
125 message: "expected integer column number in FileLineColLoc");
126 auto column = getToken().getUnsignedIntegerValue();
127 if (!column.has_value())
128 return emitError(message: "expected integer column number in FileLineColLoc");
129 consumeToken(kind: Token::integer);
130
131 loc = FileLineColLoc::get(ctx, str, *line, *column);
132 return success();
133 }
134
135 // Otherwise, this is a NameLoc.
136
137 // Check for a child location.
138 if (consumeIf(kind: Token::l_paren)) {
139 // Parse the child location.
140 LocationAttr childLoc;
141 if (parseLocationInstance(loc&: childLoc))
142 return failure();
143
144 loc = NameLoc::get(StringAttr::get(ctx, str), childLoc);
145
146 // Parse the closing ')'.
147 if (parseToken(expectedToken: Token::r_paren,
148 message: "expected ')' after child location of NameLoc"))
149 return failure();
150 } else {
151 loc = NameLoc::get(StringAttr::get(ctx, str));
152 }
153
154 return success();
155}
156
157ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
158 // Handle aliases.
159 if (getToken().is(k: Token::hash_identifier)) {
160 Attribute locAttr = parseExtendedAttr(type: Type());
161 if (!locAttr)
162 return failure();
163 if (!(loc = dyn_cast<LocationAttr>(Val&: locAttr)))
164 return emitError(message: "expected location attribute, but got") << locAttr;
165 return success();
166 }
167
168 // Handle either name or filelinecol locations.
169 if (getToken().is(k: Token::string))
170 return parseNameOrFileLineColLocation(loc);
171
172 // Bare tokens required for other cases.
173 if (!getToken().is(k: Token::bare_identifier))
174 return emitWrongTokenError(message: "expected location instance");
175
176 // Check for the 'callsite' signifying a callsite location.
177 if (getToken().getSpelling() == "callsite")
178 return parseCallSiteLocation(loc);
179
180 // If the token is 'fused', then this is a fused location.
181 if (getToken().getSpelling() == "fused")
182 return parseFusedLocation(loc);
183
184 // Check for a 'unknown' for an unknown location.
185 if (getToken().getSpelling() == "unknown") {
186 consumeToken(kind: Token::bare_identifier);
187 loc = UnknownLoc::get(getContext());
188 return success();
189 }
190
191 return emitWrongTokenError(message: "expected location instance");
192}
193

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