238 lines · cpp
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-exception6//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 <optional>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-location27/// filelinecol-location ::= string-literal ':' integer-literal28/// ':' integer-literal29/// name-location ::= string-literal30/// 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(Token::bare_identifier);37 38 // Parse the '('.39 if (parseToken(Token::l_paren, "expected '(' in callsite location"))40 return failure();41 42 // Parse the callee location.43 LocationAttr calleeLoc;44 if (parseLocationInstance(calleeLoc))45 return failure();46 47 // Parse the 'at'.48 if (getToken().isNot(Token::bare_identifier) ||49 getToken().getSpelling() != "at")50 return emitWrongTokenError("expected 'at' in callsite location");51 consumeToken(Token::bare_identifier);52 53 // Parse the caller location.54 LocationAttr callerLoc;55 if (parseLocationInstance(callerLoc))56 return failure();57 58 // Parse the ')'.59 if (parseToken(Token::r_paren, "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(Token::bare_identifier);69 70 // Try to parse the optional metadata.71 Attribute metadata;72 if (consumeIf(Token::less)) {73 metadata = parseAttribute();74 if (!metadata)75 return failure();76 77 // Parse the '>' token.78 if (parseToken(Token::greater,79 "expected '>' after fused location metadata"))80 return failure();81 }82 83 SmallVector<Location, 4> locations;84 auto parseElt = [&] {85 LocationAttr newLoc;86 if (parseLocationInstance(newLoc))87 return failure();88 locations.push_back(newLoc);89 return success();90 };91 92 if (parseCommaSeparatedList(Delimiter::Square, parseElt,93 " 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::parseNameOrFileLineColRange(LocationAttr &loc) {102 auto *ctx = getContext();103 auto str = getToken().getStringValue();104 consumeToken(Token::string);105 106 std::optional<unsigned> startLine, startColumn, endLine, endColumn;107 108 // If the next token is ':' this is a filelinecol location.109 if (consumeIf(Token::colon)) {110 // Parse the line number.111 if (getToken().isNot(Token::integer))112 return emitWrongTokenError(113 "expected integer line number in FileLineColRange");114 startLine = getToken().getUnsignedIntegerValue();115 if (!startLine)116 return emitWrongTokenError(117 "expected integer line number in FileLineColRange");118 consumeToken(Token::integer);119 120 // Parse the ':'.121 if (getToken().isNot(Token::colon)) {122 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine);123 return success();124 }125 consumeToken(Token::colon);126 127 // Parse the column number.128 if (getToken().isNot(Token::integer)) {129 return emitWrongTokenError(130 "expected integer column number in FileLineColRange");131 }132 startColumn = getToken().getUnsignedIntegerValue();133 if (!startColumn.has_value())134 return emitError("expected integer column number in FileLineColRange");135 consumeToken(Token::integer);136 137 if (!isCurrentTokenAKeyword() || getTokenSpelling() != "to") {138 loc = FileLineColLoc::get(ctx, str, *startLine, *startColumn);139 return success();140 }141 consumeToken();142 143 // Parse the line number.144 if (getToken().is(Token::integer)) {145 endLine = getToken().getUnsignedIntegerValue();146 if (!endLine) {147 return emitWrongTokenError(148 "expected integer line number in FileLineColRange");149 }150 consumeToken(Token::integer);151 }152 153 // Parse the ':'.154 if (getToken().isNot(Token::colon)) {155 return emitWrongTokenError(156 "expected either integer or `:` post `to` in FileLineColRange");157 }158 consumeToken(Token::colon);159 160 // Parse the column number.161 if (getToken().isNot(Token::integer)) {162 return emitWrongTokenError(163 "expected integer column number in FileLineColRange");164 }165 endColumn = getToken().getUnsignedIntegerValue();166 if (!endColumn.has_value())167 return emitError("expected integer column number in FileLineColRange");168 consumeToken(Token::integer);169 170 if (endLine.has_value()) {171 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine,172 *startColumn, *endLine, *endColumn);173 } else {174 loc = FileLineColRange::get(StringAttr::get(ctx, str), *startLine,175 *startColumn, *endColumn);176 }177 return success();178 }179 180 // Otherwise, this is a NameLoc.181 182 // Check for a child location.183 if (consumeIf(Token::l_paren)) {184 // Parse the child location.185 LocationAttr childLoc;186 if (parseLocationInstance(childLoc))187 return failure();188 189 loc = NameLoc::get(StringAttr::get(ctx, str), childLoc);190 191 // Parse the closing ')'.192 if (parseToken(Token::r_paren,193 "expected ')' after child location of NameLoc"))194 return failure();195 } else {196 loc = NameLoc::get(StringAttr::get(ctx, str));197 }198 199 return success();200}201 202ParseResult Parser::parseLocationInstance(LocationAttr &loc) {203 // Handle aliases.204 if (getToken().is(Token::hash_identifier)) {205 Attribute locAttr = parseExtendedAttr(Type());206 if (!locAttr)207 return failure();208 if (!(loc = dyn_cast<LocationAttr>(locAttr)))209 return emitError("expected location attribute, but got") << locAttr;210 return success();211 }212 213 // Handle either name or filelinecol locations.214 if (getToken().is(Token::string))215 return parseNameOrFileLineColRange(loc);216 217 // Bare tokens required for other cases.218 if (!getToken().is(Token::bare_identifier))219 return emitWrongTokenError("expected location instance");220 221 // Check for the 'callsite' signifying a callsite location.222 if (getToken().getSpelling() == "callsite")223 return parseCallSiteLocation(loc);224 225 // If the token is 'fused', then this is a fused location.226 if (getToken().getSpelling() == "fused")227 return parseFusedLocation(loc);228 229 // Check for a 'unknown' for an unknown location.230 if (getToken().getSpelling() == "unknown") {231 consumeToken(Token::bare_identifier);232 loc = UnknownLoc::get(getContext());233 return success();234 }235 236 return emitWrongTokenError("expected location instance");237}238