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 /// 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 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 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 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