1 // Copyright 2019 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_TORQUE_LS_MESSAGE_H_ 6 #define V8_TORQUE_LS_MESSAGE_H_ 7 8 #include "src/base/logging.h" 9 #include "src/torque/ls/json.h" 10 #include "src/torque/ls/message-macros.h" 11 #include "src/torque/source-positions.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace torque { 16 namespace ls { 17 18 // Base class for Messages and Objects that are backed by either a 19 // JsonValue or a reference to a JsonObject. 20 // Helper methods are used by macros to implement typed accessors. 21 class BaseJsonAccessor { 22 public: 23 template <class T> GetObject(const std::string & property)24 T GetObject(const std::string& property) { 25 return T(GetObjectProperty(property)); 26 } 27 HasProperty(const std::string & property)28 bool HasProperty(const std::string& property) const { 29 return object().count(property) > 0; 30 } 31 SetNull(const std::string & property)32 void SetNull(const std::string& property) { 33 object()[property] = JsonValue::JsonNull(); 34 } 35 IsNull(const std::string & property)36 bool IsNull(const std::string& property) const { 37 return HasProperty(property) && 38 object().at(property).tag == JsonValue::IS_NULL; 39 } 40 41 protected: 42 virtual const JsonObject& object() const = 0; 43 virtual JsonObject& object() = 0; 44 GetObjectProperty(const std::string & property)45 JsonObject& GetObjectProperty(const std::string& property) { 46 if (!object()[property].IsObject()) { 47 object()[property] = JsonValue::From(JsonObject{}); 48 } 49 return object()[property].ToObject(); 50 } 51 GetArrayProperty(const std::string & property)52 JsonArray& GetArrayProperty(const std::string& property) { 53 if (!object()[property].IsArray()) { 54 object()[property] = JsonValue::From(JsonArray{}); 55 } 56 return object()[property].ToArray(); 57 } 58 AddObjectElementToArrayProperty(const std::string & property)59 JsonObject& AddObjectElementToArrayProperty(const std::string& property) { 60 JsonArray& array = GetArrayProperty(property); 61 array.push_back(JsonValue::From(JsonObject{})); 62 63 return array.back().ToObject(); 64 } 65 }; 66 67 // Base class for Requests, Responses and Notifications. 68 // In contrast to "BaseObject", a Message owns the backing JsonValue of the 69 // whole object tree; i.e. value_ serves as root. 70 class Message : public BaseJsonAccessor { 71 public: Message()72 Message() { 73 value_ = JsonValue::From(JsonObject{}); 74 set_jsonrpc("2.0"); 75 } Message(JsonValue value)76 explicit Message(JsonValue value) : value_(std::move(value)) { 77 CHECK(value_.tag == JsonValue::OBJECT); 78 } 79 GetJsonValue()80 JsonValue& GetJsonValue() { return value_; } 81 JSON_STRING_ACCESSORS(jsonrpc)82 JSON_STRING_ACCESSORS(jsonrpc) 83 84 protected: 85 const JsonObject& object() const override { return value_.ToObject(); } object()86 JsonObject& object() override { return value_.ToObject(); } 87 88 private: 89 JsonValue value_; 90 }; 91 92 // Base class for complex type that might be part of a Message. 93 // Instead of creating theses directly, use the accessors on the 94 // root Message or a parent object. 95 class NestedJsonAccessor : public BaseJsonAccessor { 96 public: NestedJsonAccessor(JsonObject & object)97 explicit NestedJsonAccessor(JsonObject& object) : object_(object) {} 98 object()99 const JsonObject& object() const override { return object_; } object()100 JsonObject& object() override { return object_; } 101 102 private: 103 JsonObject& object_; 104 }; 105 106 class ResponseError : public NestedJsonAccessor { 107 public: 108 using NestedJsonAccessor::NestedJsonAccessor; 109 110 JSON_INT_ACCESSORS(code) 111 JSON_STRING_ACCESSORS(message) 112 }; 113 114 class InitializeParams : public NestedJsonAccessor { 115 public: 116 using NestedJsonAccessor::NestedJsonAccessor; 117 118 JSON_INT_ACCESSORS(processId) 119 JSON_STRING_ACCESSORS(rootPath) 120 JSON_STRING_ACCESSORS(rootUri) 121 JSON_STRING_ACCESSORS(trace) 122 }; 123 124 class FileListParams : public NestedJsonAccessor { 125 public: 126 using NestedJsonAccessor::NestedJsonAccessor; 127 128 // TODO(szuend): Implement read accessor for string 129 // arrays. "files" is managed directly. 130 }; 131 132 class FileSystemWatcher : public NestedJsonAccessor { 133 public: 134 using NestedJsonAccessor::NestedJsonAccessor; 135 136 JSON_STRING_ACCESSORS(globPattern) 137 JSON_INT_ACCESSORS(kind) 138 139 enum WatchKind { 140 kCreate = 1, 141 kChange = 2, 142 kDelete = 4, 143 144 kAll = kCreate | kChange | kDelete, 145 }; 146 }; 147 148 class DidChangeWatchedFilesRegistrationOptions : public NestedJsonAccessor { 149 public: 150 using NestedJsonAccessor::NestedJsonAccessor; 151 152 JSON_ARRAY_OBJECT_ACCESSORS(FileSystemWatcher, watchers) 153 }; 154 155 class FileEvent : public NestedJsonAccessor { 156 public: 157 using NestedJsonAccessor::NestedJsonAccessor; 158 159 JSON_STRING_ACCESSORS(uri) 160 JSON_INT_ACCESSORS(type) 161 }; 162 163 class DidChangeWatchedFilesParams : public NestedJsonAccessor { 164 public: 165 using NestedJsonAccessor::NestedJsonAccessor; 166 167 JSON_ARRAY_OBJECT_ACCESSORS(FileEvent, changes) 168 }; 169 170 class SaveOptions : public NestedJsonAccessor { 171 public: 172 using NestedJsonAccessor::NestedJsonAccessor; 173 174 JSON_BOOL_ACCESSORS(includeText) 175 }; 176 177 class TextDocumentSyncOptions : public NestedJsonAccessor { 178 public: 179 using NestedJsonAccessor::NestedJsonAccessor; 180 181 JSON_BOOL_ACCESSORS(openClose) 182 JSON_INT_ACCESSORS(change) 183 JSON_BOOL_ACCESSORS(willSave) 184 JSON_BOOL_ACCESSORS(willSaveWaitUntil) 185 JSON_OBJECT_ACCESSORS(SaveOptions, save) 186 }; 187 188 class ServerCapabilities : public NestedJsonAccessor { 189 public: 190 using NestedJsonAccessor::NestedJsonAccessor; 191 192 JSON_OBJECT_ACCESSORS(TextDocumentSyncOptions, textDocumentSync) 193 JSON_BOOL_ACCESSORS(definitionProvider) 194 JSON_BOOL_ACCESSORS(documentSymbolProvider) 195 }; 196 197 class InitializeResult : public NestedJsonAccessor { 198 public: 199 using NestedJsonAccessor::NestedJsonAccessor; 200 201 JSON_OBJECT_ACCESSORS(ServerCapabilities, capabilities) 202 }; 203 204 class Registration : public NestedJsonAccessor { 205 public: 206 using NestedJsonAccessor::NestedJsonAccessor; 207 208 JSON_STRING_ACCESSORS(id) 209 JSON_STRING_ACCESSORS(method) 210 JSON_DYNAMIC_OBJECT_ACCESSORS(registerOptions) 211 }; 212 213 class RegistrationParams : public NestedJsonAccessor { 214 public: 215 using NestedJsonAccessor::NestedJsonAccessor; 216 217 JSON_ARRAY_OBJECT_ACCESSORS(Registration, registrations) 218 }; 219 220 class JsonPosition : public NestedJsonAccessor { 221 public: 222 using NestedJsonAccessor::NestedJsonAccessor; 223 224 JSON_INT_ACCESSORS(line) 225 JSON_INT_ACCESSORS(character) 226 }; 227 228 class Range : public NestedJsonAccessor { 229 public: 230 using NestedJsonAccessor::NestedJsonAccessor; 231 232 JSON_OBJECT_ACCESSORS(JsonPosition, start) 233 JSON_OBJECT_ACCESSORS(JsonPosition, end) 234 }; 235 236 class Location : public NestedJsonAccessor { 237 public: 238 using NestedJsonAccessor::NestedJsonAccessor; 239 240 JSON_STRING_ACCESSORS(uri) JSON_OBJECT_ACCESSORS(Range,range)241 JSON_OBJECT_ACCESSORS(Range, range) 242 243 void SetTo(SourcePosition position) { 244 set_uri(SourceFileMap::AbsolutePath(position.source)); 245 range().start().set_line(position.start.line); 246 range().start().set_character(position.start.column); 247 range().end().set_line(position.end.line); 248 range().end().set_character(position.end.column); 249 } 250 }; 251 252 class TextDocumentIdentifier : public NestedJsonAccessor { 253 public: 254 using NestedJsonAccessor::NestedJsonAccessor; 255 256 JSON_STRING_ACCESSORS(uri) 257 }; 258 259 class TextDocumentPositionParams : public NestedJsonAccessor { 260 public: 261 using NestedJsonAccessor::NestedJsonAccessor; 262 263 JSON_OBJECT_ACCESSORS(TextDocumentIdentifier, textDocument) 264 JSON_OBJECT_ACCESSORS(JsonPosition, position) 265 }; 266 267 class Diagnostic : public NestedJsonAccessor { 268 public: 269 using NestedJsonAccessor::NestedJsonAccessor; 270 271 enum DiagnosticSeverity { 272 kError = 1, 273 kWarning = 2, 274 kInformation = 3, 275 kHint = 4 276 }; 277 278 JSON_OBJECT_ACCESSORS(Range, range) 279 JSON_INT_ACCESSORS(severity) 280 JSON_STRING_ACCESSORS(source) 281 JSON_STRING_ACCESSORS(message) 282 }; 283 284 class PublishDiagnosticsParams : public NestedJsonAccessor { 285 public: 286 using NestedJsonAccessor::NestedJsonAccessor; 287 288 JSON_STRING_ACCESSORS(uri) 289 JSON_ARRAY_OBJECT_ACCESSORS(Diagnostic, diagnostics) 290 }; 291 292 enum SymbolKind { 293 kFile = 1, 294 kNamespace = 3, 295 kClass = 5, 296 kMethod = 6, 297 kProperty = 7, 298 kField = 8, 299 kConstructor = 9, 300 kFunction = 12, 301 kVariable = 13, 302 kConstant = 14, 303 kStruct = 23, 304 }; 305 306 class DocumentSymbolParams : public NestedJsonAccessor { 307 public: 308 using NestedJsonAccessor::NestedJsonAccessor; 309 310 JSON_OBJECT_ACCESSORS(TextDocumentIdentifier, textDocument) 311 }; 312 313 class SymbolInformation : public NestedJsonAccessor { 314 public: 315 using NestedJsonAccessor::NestedJsonAccessor; 316 317 JSON_STRING_ACCESSORS(name) 318 JSON_INT_ACCESSORS(kind) 319 JSON_OBJECT_ACCESSORS(Location, location) 320 JSON_STRING_ACCESSORS(containerName) 321 }; 322 323 template <class T> 324 class Request : public Message { 325 public: Request(JsonValue value)326 explicit Request(JsonValue value) : Message(std::move(value)) {} Request()327 Request() : Message() {} 328 329 JSON_INT_ACCESSORS(id) 330 JSON_STRING_ACCESSORS(method) 331 JSON_OBJECT_ACCESSORS(T, params) 332 }; 333 using InitializeRequest = Request<InitializeParams>; 334 using RegistrationRequest = Request<RegistrationParams>; 335 using TorqueFileListNotification = Request<FileListParams>; 336 using GotoDefinitionRequest = Request<TextDocumentPositionParams>; 337 using DidChangeWatchedFilesNotification = Request<DidChangeWatchedFilesParams>; 338 using PublishDiagnosticsNotification = Request<PublishDiagnosticsParams>; 339 using DocumentSymbolRequest = Request<DocumentSymbolParams>; 340 341 template <class T> 342 class Response : public Message { 343 public: Response(JsonValue value)344 explicit Response(JsonValue value) : Message(std::move(value)) {} Response()345 Response() : Message() {} 346 347 JSON_INT_ACCESSORS(id) 348 JSON_OBJECT_ACCESSORS(ResponseError, error) 349 JSON_OBJECT_ACCESSORS(T, result) 350 }; 351 using InitializeResponse = Response<InitializeResult>; 352 using GotoDefinitionResponse = Response<Location>; 353 354 // Same as "Response" but the result is T[] instead of T. 355 template <class T> 356 class ResponseArrayResult : public Message { 357 public: ResponseArrayResult(JsonValue value)358 explicit ResponseArrayResult(JsonValue value) : Message(std::move(value)) {} ResponseArrayResult()359 ResponseArrayResult() : Message() {} 360 361 JSON_INT_ACCESSORS(id) 362 JSON_OBJECT_ACCESSORS(ResponseError, error) 363 JSON_ARRAY_OBJECT_ACCESSORS(T, result) 364 }; 365 using DocumentSymbolResponse = ResponseArrayResult<SymbolInformation>; 366 367 } // namespace ls 368 } // namespace torque 369 } // namespace internal 370 } // namespace v8 371 372 #endif // V8_TORQUE_LS_MESSAGE_H_ 373