brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · 7235921 Raw
307 lines · cpp
1//===-- ProtocolBase.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//===----------------------------------------------------------------------===//8 9#include "Protocol/ProtocolBase.h"10#include "llvm/ADT/StringRef.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/Support/ErrorHandling.h"13#include "llvm/Support/JSON.h"14#include <optional>15#include <utility>16 17using namespace llvm;18 19static bool mapRaw(const json::Value &Params, StringLiteral Prop,20                   std::optional<json::Value> &V, json::Path P) {21  const auto *O = Params.getAsObject();22  if (!O) {23    P.report("expected object");24    return false;25  }26  const json::Value *E = O->get(Prop);27  if (E)28    V = std::move(*E);29  return true;30}31 32namespace lldb_dap::protocol {33 34enum MessageType : unsigned {35  eMessageTypeRequest,36  eMessageTypeResponse,37  eMessageTypeEvent38};39 40bool fromJSON(const json::Value &Params, MessageType &M, json::Path P) {41  auto rawType = Params.getAsString();42  if (!rawType) {43    P.report("expected a string");44    return false;45  }46  std::optional<MessageType> type =47      StringSwitch<std::optional<MessageType>>(*rawType)48          .Case("request", eMessageTypeRequest)49          .Case("response", eMessageTypeResponse)50          .Case("event", eMessageTypeEvent)51          .Default(std::nullopt);52  if (!type) {53    P.report("unexpected value, expected 'request', 'response' or 'event'");54    return false;55  }56  M = *type;57  return true;58}59 60json::Value toJSON(const Request &R) {61  assert(R.seq != kCalculateSeq && "invalid seq");62 63  json::Object Result{64      {"type", "request"},65      {"seq", R.seq},66      {"command", R.command},67  };68 69  if (R.arguments)70    Result.insert({"arguments", R.arguments});71 72  return std::move(Result);73}74 75bool fromJSON(json::Value const &Params, Request &R, json::Path P) {76  json::ObjectMapper O(Params, P);77  if (!O)78    return false;79 80  MessageType type;81  if (!O.map("type", type) || !O.map("command", R.command) ||82      !O.map("seq", R.seq))83    return false;84 85  if (type != eMessageTypeRequest) {86    P.field("type").report("expected to be 'request'");87    return false;88  }89 90  if (R.command.empty()) {91    P.field("command").report("expected to not be ''");92    return false;93  }94 95  if (!R.seq) {96    P.field("seq").report("expected to not be '0'");97    return false;98  }99 100  return mapRaw(Params, "arguments", R.arguments, P);101}102 103bool operator==(const Request &a, const Request &b) {104  return a.seq == b.seq && a.command == b.command && a.arguments == b.arguments;105}106 107json::Value toJSON(const Response &R) {108  assert(R.seq != kCalculateSeq && "invalid seq");109 110  json::Object Result{{"type", "response"},111                      {"seq", R.seq},112                      {"command", R.command},113                      {"request_seq", R.request_seq},114                      {"success", R.success}};115 116  if (R.message) {117    assert(!R.success && "message can only be used if success is false");118    if (const auto *messageEnum = std::get_if<ResponseMessage>(&*R.message)) {119      switch (*messageEnum) {120      case eResponseMessageCancelled:121        Result.insert({"message", "cancelled"});122        break;123      case eResponseMessageNotStopped:124        Result.insert({"message", "notStopped"});125        break;126      }127    } else if (const auto *messageString =128                   std::get_if<std::string>(&*R.message)) {129      Result.insert({"message", *messageString});130    }131  }132 133  if (R.body)134    Result.insert({"body", R.body});135 136  return std::move(Result);137}138 139static bool fromJSON(json::Value const &Params,140                     std::variant<ResponseMessage, std::string> &M,141                     json::Path P) {142  auto rawMessage = Params.getAsString();143  if (!rawMessage) {144    P.report("expected a string");145    return false;146  }147  std::optional<ResponseMessage> message =148      StringSwitch<std::optional<ResponseMessage>>(*rawMessage)149          .Case("cancelled", eResponseMessageCancelled)150          .Case("notStopped", eResponseMessageNotStopped)151          .Default(std::nullopt);152  if (message)153    M = *message;154  else if (!rawMessage->empty())155    M = rawMessage->str();156  return true;157}158 159bool fromJSON(json::Value const &Params, Response &R, json::Path P) {160  json::ObjectMapper O(Params, P);161  if (!O)162    return false;163 164  MessageType type;165  if (!O.map("type", type) || !O.map("seq", R.seq) ||166      !O.map("command", R.command) || !O.map("request_seq", R.request_seq))167    return false;168 169  if (type != eMessageTypeResponse) {170    P.field("type").report("expected to be 'response'");171    return false;172  }173 174  if (R.command.empty()) {175    P.field("command").report("expected to not be empty");176    return false;177  }178 179  return O.map("success", R.success) && O.map("message", R.message) &&180         mapRaw(Params, "body", R.body, P);181}182 183bool operator==(const Response &a, const Response &b) {184  return a.request_seq == b.request_seq && a.command == b.command &&185         a.success == b.success && a.message == b.message && a.body == b.body;186}187 188json::Value toJSON(const ErrorMessage &EM) {189  json::Object Result{{"id", EM.id}, {"format", EM.format}};190 191  if (EM.variables) {192    json::Object variables;193    for (auto &var : *EM.variables)194      variables[var.first] = var.second;195    Result.insert({"variables", std::move(variables)});196  }197  if (EM.sendTelemetry)198    Result.insert({"sendTelemetry", EM.sendTelemetry});199  if (EM.showUser)200    Result.insert({"showUser", EM.showUser});201  if (EM.url)202    Result.insert({"url", EM.url});203  if (EM.urlLabel)204    Result.insert({"urlLabel", EM.urlLabel});205 206  return std::move(Result);207}208 209bool fromJSON(json::Value const &Params, ErrorMessage &EM, json::Path P) {210  json::ObjectMapper O(Params, P);211  return O && O.map("id", EM.id) && O.map("format", EM.format) &&212         O.map("variables", EM.variables) &&213         O.map("sendTelemetry", EM.sendTelemetry) &&214         O.map("showUser", EM.showUser) && O.map("url", EM.url) &&215         O.map("urlLabel", EM.urlLabel);216}217 218json::Value toJSON(const Event &E) {219  assert(E.seq != kCalculateSeq && "invalid seq");220 221  json::Object Result{222      {"type", "event"},223      {"seq", E.seq},224      {"event", E.event},225  };226 227  if (E.body)228    Result.insert({"body", E.body});229 230  return std::move(Result);231}232 233bool fromJSON(json::Value const &Params, Event &E, json::Path P) {234  json::ObjectMapper O(Params, P);235  if (!O)236    return false;237 238  MessageType type;239  if (!O.map("type", type) || !O.map("seq", E.seq) || !O.map("event", E.event))240    return false;241 242  if (type != eMessageTypeEvent) {243    P.field("type").report("expected to be 'event'");244    return false;245  }246 247  if (E.event.empty()) {248    P.field("event").report("expected to not be empty");249    return false;250  }251 252  return mapRaw(Params, "body", E.body, P);253}254 255bool operator==(const Event &a, const Event &b) {256  return a.event == b.event && a.body == b.body;257}258 259bool fromJSON(const json::Value &Params, Message &PM, json::Path P) {260  json::ObjectMapper O(Params, P);261  if (!O)262    return false;263 264  MessageType type;265  if (!O.map("type", type))266    return false;267 268  switch (type) {269  case eMessageTypeRequest: {270    Request req;271    if (!fromJSON(Params, req, P))272      return false;273    PM = std::move(req);274    return true;275  }276  case eMessageTypeResponse: {277    Response resp;278    if (!fromJSON(Params, resp, P))279      return false;280    PM = std::move(resp);281    return true;282  }283  case eMessageTypeEvent:284    Event evt;285    if (!fromJSON(Params, evt, P))286      return false;287    PM = std::move(evt);288    return true;289  }290  llvm_unreachable("unhandled message type request.");291}292 293json::Value toJSON(const Message &M) {294  return std::visit([](auto &M) { return toJSON(M); }, M);295}296 297json::Value toJSON(const ErrorResponseBody &E) {298  json::Object result{};299 300  if (E.error)301    result.insert({"error", *E.error});302 303  return result;304}305 306} // namespace lldb_dap::protocol307