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