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