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 emitError("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 emitError("expected valid attribute metadata");
70 // Parse the '>' token.
71 if (parseToken(Token::greater,
72 "expected '>' after fused location metadata"))
73 return failure();
74 }
75
76 SmallVector<Location, 4> locations;
77 auto parseElt = [&] {
78 LocationAttr newLoc;
79 if (parseLocationInstance(newLoc))
80 return failure();
81 locations.push_back(newLoc);
82 return success();
83 };
84
85 if (parseToken(Token::l_square, "expected '[' in fused location") ||
86 parseCommaSeparatedList(parseElt) ||
87 parseToken(Token::r_square, "expected ']' 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 emitError("expected integer line number in FileLineColLoc");
105 auto line = getToken().getUnsignedIntegerValue();
106 if (!line.hasValue())
107 return emitError("expected integer line number in FileLineColLoc");
108 consumeToken(Token::integer);
109
110 // Parse the ':'.
111 if (parseToken(Token::colon, "expected ':' in FileLineColLoc"))
112 return failure();
113
114 // Parse the column number.
115 if (getToken().isNot(Token::integer))
116 return emitError("expected integer column number in FileLineColLoc");
117 auto column = getToken().getUnsignedIntegerValue();
118 if (!column.hasValue())
119 return emitError("expected integer column number in FileLineColLoc");
120 consumeToken(Token::integer);
121
122 loc = FileLineColLoc::get(ctx, str, line.getValue(), column.getValue());
123 return success();
124 }
125
126 // Otherwise, this is a NameLoc.
127
128 // Check for a child location.
129 if (consumeIf(Token::l_paren)) {
130 auto childSourceLoc = getToken().getLoc();
131
132 // Parse the child location.
133 LocationAttr childLoc;
134 if (parseLocationInstance(childLoc))
135 return failure();
136
137 // The child must not be another NameLoc.
138 if (childLoc.isa<NameLoc>())
139 return emitError(childSourceLoc,
140 "child of NameLoc cannot be another NameLoc");
141 loc = NameLoc::get(Identifier::get(str, ctx), childLoc);
142
143 // Parse the closing ')'.
144 if (parseToken(Token::r_paren,
145 "expected ')' after child location of NameLoc"))
146 return failure();
147 } else {
148 loc = NameLoc::get(Identifier::get(str, ctx));
149 }
150
151 return success();
152 }
153
parseLocationInstance(LocationAttr & loc)154 ParseResult Parser::parseLocationInstance(LocationAttr &loc) {
155 // Handle either name or filelinecol locations.
156 if (getToken().is(Token::string))
157 return parseNameOrFileLineColLocation(loc);
158
159 // Bare tokens required for other cases.
160 if (!getToken().is(Token::bare_identifier))
161 return emitError("expected location instance");
162
163 // Check for the 'callsite' signifying a callsite location.
164 if (getToken().getSpelling() == "callsite")
165 return parseCallSiteLocation(loc);
166
167 // If the token is 'fused', then this is a fused location.
168 if (getToken().getSpelling() == "fused")
169 return parseFusedLocation(loc);
170
171 // Check for a 'unknown' for an unknown location.
172 if (getToken().getSpelling() == "unknown") {
173 consumeToken(Token::bare_identifier);
174 loc = UnknownLoc::get(getContext());
175 return success();
176 }
177
178 return emitError("expected location instance");
179 }
180