|  | //===- LocationParser.cpp - MLIR Location Parser  -------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Parser.h" | 
|  | #include "Token.h" | 
|  | #include "mlir/IR/Attributes.h" | 
|  | #include "mlir/IR/BuiltinAttributes.h" | 
|  | #include "mlir/IR/Location.h" | 
|  | #include "mlir/Support/LLVM.h" | 
|  | #include <optional> | 
|  |  | 
|  | using namespace mlir; | 
|  | using namespace mlir::detail; | 
|  |  | 
|  | /// Specific location instances. | 
|  | /// | 
|  | /// location-inst ::= filelinecol-location | | 
|  | ///                   name-location | | 
|  | ///                   callsite-location | | 
|  | ///                   fused-location | | 
|  | ///                   unknown-location | 
|  | /// filelinecol-location ::= string-literal ':' integer-literal | 
|  | ///                                         ':' integer-literal | 
|  | /// name-location ::= string-literal | 
|  | /// callsite-location ::= 'callsite' '(' location-inst 'at' location-inst ')' | 
|  | /// fused-location ::= fused ('<' attribute-value '>')? | 
|  | ///                    '[' location-inst (location-inst ',')* ']' | 
|  | /// unknown-location ::= 'unknown' | 
|  | /// | 
|  | ParseResult Parser::parseCallSiteLocation(LocationAttr &loc) { | 
|  | consumeToken(Token::bare_identifier); | 
|  |  | 
|  | // Parse the '('. | 
|  | if (parseToken(Token::l_paren, "expected '(' in callsite location")) | 
|  | return failure(); | 
|  |  | 
|  | // Parse the callee location. | 
|  | LocationAttr calleeLoc; | 
|  | if (parseLocationInstance(calleeLoc)) | 
|  | return failure(); | 
|  |  | 
|  | // Parse the 'at'. | 
|  | if (getToken().isNot(Token::bare_identifier) || | 
|  | getToken().getSpelling() != "at") | 
|  | return emitWrongTokenError("expected 'at' in callsite location"); | 
|  | consumeToken(Token::bare_identifier); | 
|  |  | 
|  | // Parse the caller location. | 
|  | LocationAttr callerLoc; | 
|  | if (parseLocationInstance(callerLoc)) | 
|  | return failure(); | 
|  |  | 
|  | // Parse the ')'. | 
|  | if (parseToken(Token::r_paren, "expected ')' in callsite location")) | 
|  | return failure(); | 
|  |  | 
|  | // Return the callsite location. | 
|  | loc = CallSiteLoc::get(calleeLoc, callerLoc); | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | ParseResult Parser::parseFusedLocation(LocationAttr &loc) { | 
|  | consumeToken(Token::bare_identifier); | 
|  |  | 
|  | // Try to parse the optional metadata. | 
|  | Attribute metadata; | 
|  | if (consumeIf(Token::less)) { | 
|  | metadata = parseAttribute(); | 
|  | if (!metadata) | 
|  | return failure(); | 
|  |  | 
|  | // Parse the '>' token. | 
|  | if (parseToken(Token::greater, | 
|  | "expected '>' after fused location metadata")) | 
|  | return failure(); | 
|  | } | 
|  |  | 
|  | SmallVector<Location, 4> locations; | 
|  | auto parseElt = [&] { | 
|  | LocationAttr newLoc; | 
|  | if (parseLocationInstance(newLoc)) | 
|  | return failure(); | 
|  | locations.push_back(newLoc); | 
|  | return success(); | 
|  | }; | 
|  |  | 
|  | if (parseCommaSeparatedList(Delimiter::Square, parseElt, | 
|  | " in fused location")) | 
|  | return failure(); | 
|  |  | 
|  | // Return the fused location. | 
|  | loc = FusedLoc::get(locations, metadata, getContext()); | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | ParseResult Parser::parseNameOrFileLineColRange(LocationAttr &loc) { | 
|  | auto *ctx = getContext(); | 
|  | auto str = getToken().getStringValue(); | 
|  | consumeToken(Token::string); | 
|  |  | 
|  | std::optional<unsigned> startLine, startColumn, endLine, endColumn; | 
|  |  | 
|  | // If the next token is ':' this is a filelinecol location. | 
|  | if (consumeIf(Token::colon)) { | 
|  | // Parse the line number. | 
|  | if (getToken().isNot(Token::integer)) | 
|  | return emitWrongTokenError( | 
|  | "expected integer line number in FileLineColRange"); | 
|  | startLine = getToken().getUnsignedIntegerValue(); | 
|  | if (!startLine) | 
|  | return emitWrongTokenError( | 
|  | "expected integer line number in FileLineColRange"); | 
|  | consumeToken(Token::integer); | 
|  |  | 
|  | // Parse the ':'. | 
|  | if (getToken().isNot(Token::colon)) { | 
|  | loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine); | 
|  | return success(); | 
|  | } | 
|  | consumeToken(Token::colon); | 
|  |  | 
|  | // Parse the column number. | 
|  | if (getToken().isNot(Token::integer)) { | 
|  | return emitWrongTokenError( | 
|  | "expected integer column number in FileLineColRange"); | 
|  | } | 
|  | startColumn = getToken().getUnsignedIntegerValue(); | 
|  | if (!startColumn.has_value()) | 
|  | return emitError("expected integer column number in FileLineColRange"); | 
|  | consumeToken(Token::integer); | 
|  |  | 
|  | if (!isCurrentTokenAKeyword() || getTokenSpelling() != "to") { | 
|  | loc = FileLineColLoc::get(ctx, str, *startLine, *startColumn); | 
|  | return success(); | 
|  | } | 
|  | consumeToken(); | 
|  |  | 
|  | // Parse the line number. | 
|  | if (getToken().is(Token::integer)) { | 
|  | endLine = getToken().getUnsignedIntegerValue(); | 
|  | if (!endLine) { | 
|  | return emitWrongTokenError( | 
|  | "expected integer line number in FileLineColRange"); | 
|  | } | 
|  | consumeToken(Token::integer); | 
|  | } | 
|  |  | 
|  | // Parse the ':'. | 
|  | if (getToken().isNot(Token::colon)) { | 
|  | return emitWrongTokenError( | 
|  | "expected either integer or `:` post `to` in FileLineColRange"); | 
|  | } | 
|  | consumeToken(Token::colon); | 
|  |  | 
|  | // Parse the column number. | 
|  | if (getToken().isNot(Token::integer)) { | 
|  | return emitWrongTokenError( | 
|  | "expected integer column number in FileLineColRange"); | 
|  | } | 
|  | endColumn = getToken().getUnsignedIntegerValue(); | 
|  | if (!endColumn.has_value()) | 
|  | return emitError("expected integer column number in FileLineColRange"); | 
|  | consumeToken(Token::integer); | 
|  |  | 
|  | if (endLine.has_value()) { | 
|  | loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine, | 
|  | *startColumn, *endLine, *endColumn); | 
|  | } else { | 
|  | loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine, | 
|  | *startColumn, *endColumn); | 
|  | } | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | // Otherwise, this is a NameLoc. | 
|  |  | 
|  | // Check for a child location. | 
|  | if (consumeIf(Token::l_paren)) { | 
|  | // Parse the child location. | 
|  | LocationAttr childLoc; | 
|  | if (parseLocationInstance(childLoc)) | 
|  | return failure(); | 
|  |  | 
|  | loc = NameLoc::get(StringAttr::get(ctx, str), childLoc); | 
|  |  | 
|  | // Parse the closing ')'. | 
|  | if (parseToken(Token::r_paren, | 
|  | "expected ')' after child location of NameLoc")) | 
|  | return failure(); | 
|  | } else { | 
|  | loc = NameLoc::get(StringAttr::get(ctx, str)); | 
|  | } | 
|  |  | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | ParseResult Parser::parseLocationInstance(LocationAttr &loc) { | 
|  | // Handle aliases. | 
|  | if (getToken().is(Token::hash_identifier)) { | 
|  | Attribute locAttr = parseExtendedAttr(Type()); | 
|  | if (!locAttr) | 
|  | return failure(); | 
|  | if (!(loc = dyn_cast<LocationAttr>(locAttr))) | 
|  | return emitError("expected location attribute, but got") << locAttr; | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | // Handle either name or filelinecol locations. | 
|  | if (getToken().is(Token::string)) | 
|  | return parseNameOrFileLineColRange(loc); | 
|  |  | 
|  | // Bare tokens required for other cases. | 
|  | if (!getToken().is(Token::bare_identifier)) | 
|  | return emitWrongTokenError("expected location instance"); | 
|  |  | 
|  | // Check for the 'callsite' signifying a callsite location. | 
|  | if (getToken().getSpelling() == "callsite") | 
|  | return parseCallSiteLocation(loc); | 
|  |  | 
|  | // If the token is 'fused', then this is a fused location. | 
|  | if (getToken().getSpelling() == "fused") | 
|  | return parseFusedLocation(loc); | 
|  |  | 
|  | // Check for a 'unknown' for an unknown location. | 
|  | if (getToken().getSpelling() == "unknown") { | 
|  | consumeToken(Token::bare_identifier); | 
|  | loc = UnknownLoc::get(getContext()); | 
|  | return success(); | 
|  | } | 
|  |  | 
|  | return emitWrongTokenError("expected location instance"); | 
|  | } |