brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.9 KiB · e0202a2 Raw
169 lines · cpp
1//===-- DILLexer.cpp ------------------------------------------------------===//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// This implements the recursive descent parser for the Data Inspection8// Language (DIL), and its helper functions, which will eventually underlie the9// 'frame variable' command. The language that this parser recognizes is10// described in lldb/docs/dil-expr-lang.ebnf11//12//===----------------------------------------------------------------------===//13 14#include "lldb/ValueObject/DILLexer.h"15#include "lldb/Utility/Status.h"16#include "lldb/ValueObject/DILParser.h"17#include "llvm/ADT/StringSwitch.h"18 19namespace lldb_private::dil {20 21llvm::StringRef Token::GetTokenName(Kind kind) {22  switch (kind) {23  case Kind::amp:24    return "amp";25  case Kind::arrow:26    return "arrow";27  case Kind::coloncolon:28    return "coloncolon";29  case Kind::eof:30    return "eof";31  case Kind::float_constant:32    return "float_constant";33  case Kind::identifier:34    return "identifier";35  case Kind::integer_constant:36    return "integer_constant";37  case Kind::kw_false:38    return "false";39  case Kind::kw_true:40    return "true";41  case Kind::l_paren:42    return "l_paren";43  case Kind::l_square:44    return "l_square";45  case Kind::minus:46    return "minus";47  case Kind::period:48    return "period";49  case Kind::plus:50    return "plus";51  case Kind::r_paren:52    return "r_paren";53  case Kind::r_square:54    return "r_square";55  case Token::star:56    return "star";57  }58  llvm_unreachable("Unknown token name");59}60 61static bool IsLetter(char c) {62  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');63}64 65static bool IsDigit(char c) { return '0' <= c && c <= '9'; }66 67// A word starts with a letter, underscore, or dollar sign, followed by68// letters ('a'..'z','A'..'Z'), digits ('0'..'9'), and/or  underscores.69static std::optional<llvm::StringRef> IsWord(llvm::StringRef expr,70                                             llvm::StringRef &remainder) {71  // Find the longest prefix consisting of letters, digits, underscors and72  // '$'. If it doesn't start with a digit, then it's a word.73  llvm::StringRef candidate = remainder.take_while(74      [](char c) { return IsDigit(c) || IsLetter(c) || c == '_' || c == '$'; });75  if (candidate.empty() || IsDigit(candidate[0]))76    return std::nullopt;77  remainder = remainder.drop_front(candidate.size());78  return candidate;79}80 81static bool IsNumberBodyChar(char ch) {82  return IsDigit(ch) || IsLetter(ch) || ch == '.';83}84 85static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder,86                                               bool &isFloat) {87  llvm::StringRef tail = remainder;88  llvm::StringRef body = tail.take_while(IsNumberBodyChar);89  size_t dots = body.count('.');90  if (dots > 1 || dots == body.size())91    return std::nullopt;92  if (IsDigit(body.front()) || (body[0] == '.' && IsDigit(body[1]))) {93    isFloat = dots == 1;94    tail = tail.drop_front(body.size());95    bool isHex = body.contains_insensitive('x');96    bool hasExp = !isHex && body.contains_insensitive('e');97    bool hasHexExp = isHex && body.contains_insensitive('p');98    if (hasExp || hasHexExp) {99      isFloat = true; // This marks numbers like 0x1p1 and 1e1 as float100      if (body.ends_with_insensitive("e") || body.ends_with_insensitive("p"))101        if (tail.consume_front("+") || tail.consume_front("-"))102          tail = tail.drop_while(IsNumberBodyChar);103    }104    size_t number_length = remainder.size() - tail.size();105    llvm::StringRef number = remainder.take_front(number_length);106    remainder = remainder.drop_front(number_length);107    return number;108  }109  return std::nullopt;110}111 112llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr) {113  std::vector<Token> tokens;114  llvm::StringRef remainder = expr;115  do {116    if (llvm::Expected<Token> t = Lex(expr, remainder)) {117      tokens.push_back(std::move(*t));118    } else {119      return t.takeError();120    }121  } while (tokens.back().GetKind() != Token::eof);122  return DILLexer(expr, std::move(tokens));123}124 125llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,126                                    llvm::StringRef &remainder) {127  // Skip over whitespace (spaces).128  remainder = remainder.ltrim();129  llvm::StringRef::iterator cur_pos = remainder.begin();130 131  // Check to see if we've reached the end of our input string.132  if (remainder.empty())133    return Token(Token::eof, "", (uint32_t)expr.size());134 135  uint32_t position = cur_pos - expr.begin();136  bool isFloat = false;137  std::optional<llvm::StringRef> maybe_number = IsNumber(remainder, isFloat);138  if (maybe_number) {139    auto kind = isFloat ? Token::float_constant : Token::integer_constant;140    return Token(kind, maybe_number->str(), position);141  }142  std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder);143  if (maybe_word) {144    llvm::StringRef word = *maybe_word;145    Token::Kind kind = llvm::StringSwitch<Token::Kind>(word)146                           .Case("false", Token::kw_false)147                           .Case("true", Token::kw_true)148                           .Default(Token::identifier);149    return Token(kind, word.str(), position);150  }151 152  constexpr std::pair<Token::Kind, const char *> operators[] = {153      {Token::amp, "&"},      {Token::arrow, "->"},   {Token::coloncolon, "::"},154      {Token::l_paren, "("},  {Token::l_square, "["}, {Token::minus, "-"},155      {Token::period, "."},   {Token::plus, "+"},     {Token::r_paren, ")"},156      {Token::r_square, "]"}, {Token::star, "*"},157  };158  for (auto [kind, str] : operators) {159    if (remainder.consume_front(str))160      return Token(kind, str, position);161  }162 163  // Unrecognized character(s) in string; unable to lex it.164  return llvm::make_error<DILDiagnosticError>(expr, "unrecognized token",165                                              position);166}167 168} // namespace lldb_private::dil169