Skip to content

Commit a11bb83

Browse files
authored
chore: Made the LSP types views on json.
1 parent 3d637d1 commit a11bb83

File tree

8 files changed

+8989
-2730
lines changed

8 files changed

+8989
-2730
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@
3939
"update-tests": "zx scripts/update-tests.mjs",
4040
"cxx-gen-ast": "node packages/cxx-gen-ast",
4141
"cxx-gen-lsp": "node packages/cxx-gen-lsp packages/cxx-gen-lsp/metaModel.json packages/cxx-gen-lsp -o src/lsp/cxx/lsp",
42-
"download-lsp-models": "zx scripts/download-lsp-models.mjs"
42+
"download-lsp-model": "zx scripts/download-lsp-model.mjs"
4343
}
4444
}

packages/cxx-gen-lsp/src/gen_fwd_h.ts

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,24 @@ using Pattern = std::string;
3131
3232
class LSPObject {
3333
public:
34-
explicit LSPObject(json repr): repr_(std::move(repr)) {}
34+
explicit LSPObject(json& repr): repr_(&repr) {}
3535
36-
[[nodiscard]] operator const json&() const { return repr_; }
36+
[[nodiscard]] operator const json&() const { return *repr_; }
37+
[[nodiscard]] auto get() const -> json& { return *repr_; }
3738
3839
protected:
39-
json repr_;
40+
json* repr_{nullptr};
4041
};
4142
4243
template <typename T>
4344
class Vector final : public LSPObject {
4445
public:
4546
using LSPObject::LSPObject;
4647
47-
[[nodiscard]] explicit operator bool() const { return repr_.is_array(); }
48-
[[nodiscard]] auto size() const -> std::size_t { return repr_.size(); }
49-
[[nodiscard]] auto empty() const -> bool { return repr_.empty(); }
50-
[[nodiscard]] auto at(int index) const -> const T& { return repr_[index]; }
48+
[[nodiscard]] explicit operator bool() const { return repr_->is_array(); }
49+
[[nodiscard]] auto size() const -> std::size_t { return repr_->size(); }
50+
[[nodiscard]] auto empty() const -> bool { return repr_->empty(); }
51+
[[nodiscard]] auto at(int index) const -> const T& { return repr_->at(index); }
5152
};
5253
5354
namespace details {
@@ -57,7 +58,7 @@ struct TryEmplace;
5758
5859
template <std::derived_from<LSPObject> T>
5960
struct TryEmplace<T> {
60-
auto operator()(auto& result, const json& value) const -> bool {
61+
auto operator()(auto& result, json& value) const -> bool {
6162
auto obj = T{value};
6263
if (!obj) return false;
6364
result.template emplace<T>(std::move(obj));
@@ -66,7 +67,7 @@ struct TryEmplace<T> {
6667
};
6768
6869
template <typename... Ts>
69-
auto try_emplace(std::variant<Ts...>& result, const json& value) -> bool {
70+
auto try_emplace(std::variant<Ts...>& result, json& value) -> bool {
7071
return (details::TryEmplace<Ts>{}(result, value) || ...);
7172
}
7273
@@ -77,7 +78,7 @@ struct TryEmplace<std::monostate> {
7778
7879
template <>
7980
struct TryEmplace<std::nullptr_t> {
80-
auto operator()(auto& result, const json& value) const -> bool {
81+
auto operator()(auto& result, json& value) const -> bool {
8182
if (!value.is_null()) return false;
8283
result.template emplace<std::nullptr_t>(nullptr);
8384
return true;
@@ -86,7 +87,7 @@ struct TryEmplace<std::nullptr_t> {
8687
8788
template <>
8889
struct TryEmplace<bool> {
89-
auto operator()(auto& result, const json& value) const -> bool {
90+
auto operator()(auto& result, json& value) const -> bool {
9091
if (!value.is_boolean()) return false;
9192
result.template emplace<bool>(value);
9293
return true;
@@ -95,7 +96,7 @@ struct TryEmplace<bool> {
9596
9697
template <>
9798
struct TryEmplace<int> {
98-
auto operator()(auto& result, const json& value) const -> bool {
99+
auto operator()(auto& result, json& value) const -> bool {
99100
if (!value.is_number_integer()) return false;
100101
result.template emplace<int>(value);
101102
return true;
@@ -104,7 +105,7 @@ struct TryEmplace<int> {
104105
105106
template <>
106107
struct TryEmplace<long> {
107-
auto operator()(auto& result, const json& value) const -> bool {
108+
auto operator()(auto& result, json& value) const -> bool {
108109
if (!value.is_number_integer()) return false;
109110
result.template emplace<long>(value);
110111
return true;
@@ -113,7 +114,7 @@ struct TryEmplace<long> {
113114
114115
template <>
115116
struct TryEmplace<double> {
116-
auto operator()(auto& result, const json& value) const -> bool {
117+
auto operator()(auto& result, json& value) const -> bool {
117118
if (!value.is_number_float()) return false;
118119
result.template emplace<double>(value);
119120
return true;
@@ -122,7 +123,7 @@ struct TryEmplace<double> {
122123
123124
template <>
124125
struct TryEmplace<std::string> {
125-
auto operator()(auto& result, const json& value) const -> bool {
126+
auto operator()(auto& result, json& value) const -> bool {
126127
if (!value.is_string()) return false;
127128
result.template emplace<std::string>(value);
128129
return true;
@@ -131,31 +132,32 @@ struct TryEmplace<std::string> {
131132
132133
template <typename... Ts>
133134
struct TryEmplace<std::variant<Ts...>> {
134-
auto operator()(auto& result, const json& value) const -> bool {
135+
auto operator()(auto& result, json& value) const -> bool {
135136
return try_emplace(result, value);
136137
}
137138
};
138139
139140
template <typename... Ts>
140141
struct TryEmplace<std::tuple<Ts...>> {
141-
auto operator()(auto& result, const json& value) const -> bool {
142+
auto operator()(auto& result, json& value) const -> bool {
142143
lsp_runtime_error("todo: TryEmplace<std::tuple<Ts...>>");
143144
return false;
144145
}
145146
};
146147
147148
template <>
148149
struct TryEmplace<json> {
149-
auto operator()(auto& result, const json& value) const -> bool {
150+
auto operator()(auto& result, json& value) const -> bool {
150151
result = value;
151152
return true;
152153
}
153154
};
154155
155156
template <>
156157
struct TryEmplace<TextDocumentSyncKind> {
157-
auto operator()(auto& result, const json& value) const -> bool {
158-
lsp_runtime_error("todo: TextDocumentSyncKind<json>");
158+
auto operator()(auto& result, json& value) const -> bool {
159+
if (!value.is_number_integer()) return false;
160+
result = TextDocumentSyncKind(value.get<int>());
159161
return true;
160162
}
161163
};
@@ -167,12 +169,12 @@ class Vector<std::variant<Ts...>> final : public LSPObject {
167169
public:
168170
using LSPObject::LSPObject;
169171
170-
[[nodiscard]] explicit operator bool() const { return repr_.is_array(); }
171-
[[nodiscard]] auto size() const -> std::size_t { return repr_.size(); }
172-
[[nodiscard]] auto empty() const -> bool { return repr_.empty(); }
172+
[[nodiscard]] explicit operator bool() const { return repr_->is_array(); }
173+
[[nodiscard]] auto size() const -> std::size_t { return repr_->size(); }
174+
[[nodiscard]] auto empty() const -> bool { return repr_->empty(); }
173175
[[nodiscard]] auto at(int index) const -> std::variant<Ts...> {
174176
std::variant<Ts...> result;
175-
details::try_emplace(result, repr_[index]);
177+
details::try_emplace(result, repr_->at(index));
176178
return result;
177179
}
178180
};
@@ -182,24 +184,24 @@ class Map final : public LSPObject {
182184
public:
183185
using LSPObject::LSPObject;
184186
185-
[[nodiscard]] explicit operator bool() const { return repr_.is_object(); }
186-
[[nodiscard]] auto size() const -> std::size_t { return repr_.size(); }
187-
[[nodiscard]] auto empty() const -> bool { return repr_.empty(); }
188-
[[nodiscard]] auto at(const Key& key) const -> const Value& { return repr_[key]; }
187+
[[nodiscard]] explicit operator bool() const { return repr_->is_object(); }
188+
[[nodiscard]] auto size() const -> std::size_t { return repr_->size(); }
189+
[[nodiscard]] auto empty() const -> bool { return repr_->empty(); }
190+
[[nodiscard]] auto at(const Key& key) const -> const Value& { return repr_->at(key); }
189191
};
190192
191193
template <typename Key, typename... Ts>
192194
class Map<Key, std::variant<Ts...>> final : public LSPObject {
193195
public:
194196
using LSPObject::LSPObject;
195197
196-
[[nodiscard]] explicit operator bool() const { return repr_.is_object(); }
197-
[[nodiscard]] auto size() const -> std::size_t { return repr_.size(); }
198-
[[nodiscard]] auto empty() const -> bool { return repr_.empty(); }
198+
[[nodiscard]] explicit operator bool() const { return repr_->is_object(); }
199+
[[nodiscard]] auto size() const -> std::size_t { return repr_->size(); }
200+
[[nodiscard]] auto empty() const -> bool { return repr_->empty(); }
199201
200202
[[nodiscard]] auto at(const Key& key) const -> std::variant<Ts...> {
201203
std::variant<Ts...> result;
202-
details::try_emplace(result, repr_[key]);
204+
details::try_emplace(result, repr_->at(key));
203205
return result;
204206
}
205207
};

packages/cxx-gen-lsp/src/gen_types_cc.ts

Lines changed: 114 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ class TypeGenerator {
113113
}
114114

115115
generateGetters({ structure, properties }: { structure: Structure; properties: Property[] }) {
116-
const typeName = structure.name;
117-
118116
properties.forEach((property) => {
119117
this.beginPropertyGetter({ structure, property });
120118
this.generatePropertyGetter({ structure, property });
@@ -125,15 +123,15 @@ class TypeGenerator {
125123
generateValidator({ structure, properties }: { structure: Structure; properties: Property[] }) {
126124
this.emit();
127125
this.emit(`${structure.name}::operator bool() const {`);
128-
this.emit(`if (!repr_.is_object() || repr_.is_null()) return false;`);
126+
this.emit(`if (!repr_->is_object() || repr_->is_null()) return false;`);
129127

130128
const requiredProperties = properties.filter((p) => !p.optional);
131129

132130
requiredProperties.forEach(({ name, type }) => {
133-
this.emit(`if (!repr_.contains("${name}")) return false;`);
131+
this.emit(`if (!repr_->contains("${name}")) return false;`);
134132

135133
if (type.kind === "stringLiteral") {
136-
this.emit(`if (repr_["${name}"] != "${type.value}")`);
134+
this.emit(`if ((*repr_)["${name}"] != "${type.value}")`);
137135
this.emit(` return false;`);
138136
}
139137
});
@@ -149,11 +147,11 @@ class TypeGenerator {
149147
this.emit(`auto ${structure.name}::${property.name}() const -> ${returnType} {`);
150148

151149
if (property.optional) {
152-
this.emit(`if (!repr_.contains("${property.name}")) return std::nullopt;`);
150+
this.emit(`if (!repr_->contains("${property.name}")) return std::nullopt;`);
153151
this.emit();
154152
}
155153

156-
this.emit(`const auto& value = repr_["${property.name}"];`);
154+
this.emit(`auto& value = (*repr_)["${property.name}"];`);
157155
this.emit();
158156
}
159157

@@ -216,7 +214,7 @@ class TypeGenerator {
216214
this.emit(`lsp_runtime_error("${structure.name}::${property.name}: not implement yet");`);
217215
}
218216

219-
generatePropertyGetterBase({ structure, property }: { structure: Structure; property: Property }): boolean {
217+
generatePropertyGetterBase({ property }: { structure: Structure; property: Property }): boolean {
220218
if (property.type.kind !== "base") return false;
221219

222220
switch (property.type.name) {
@@ -323,13 +321,117 @@ class TypeGenerator {
323321
generateSetters({ structure, properties }: { structure: Structure; properties: Property[] }) {
324322
const typeName = structure.name;
325323

326-
properties.forEach(({ name, type, optional }) => {
327-
const argumentType = this.getPropertyType({ type, optional });
324+
properties.forEach((property) => {
325+
const argumentType = this.getPropertyType(property);
328326
this.emit();
329-
this.emit(`auto ${typeName}::${name}(${argumentType} ${name})`);
330-
this.emit(`-> ${typeName}& { return *this; }`);
327+
this.emit(`auto ${typeName}::${property.name}(${argumentType} ${property.name})`);
328+
this.emit(`-> ${typeName}& {`);
329+
330+
if (property.optional) {
331+
this.emit(`if (!${property.name}.has_value()) {`);
332+
this.emit(`repr_->erase("${property.name}");`);
333+
this.emit(`return *this;`);
334+
this.emit(`}`);
335+
}
336+
337+
this.generatePropertySetter({ property, structure });
338+
339+
this.emit(`return *this;`);
340+
this.emit(`}`);
331341
});
332342
}
343+
344+
private generatePropertySetter({ property, structure }: { property: Property; structure: Structure }): void {
345+
const typeName = structure.name;
346+
const value = property.optional ? `${property.name}.value()` : property.name;
347+
348+
switch (property.type.kind) {
349+
case "base":
350+
this.emit(`repr_->emplace("${property.name}", std::move(${value}));`);
351+
return;
352+
353+
case "reference":
354+
if (!this.generatePropertySetterReference({ structure, property, value })) break;
355+
return;
356+
357+
case "or":
358+
if (!this.generatePropertySetterOr({ structure, property, value })) break;
359+
return;
360+
361+
default:
362+
break;
363+
} // switch
364+
365+
this.emit(`lsp_runtime_error("${typeName}::${property.name}: not implement yet");`);
366+
}
367+
368+
generatePropertySetterReference({
369+
property,
370+
value,
371+
}: {
372+
structure: Structure;
373+
property: Property;
374+
value: string;
375+
}): boolean {
376+
if (property.type.kind !== "reference") return false;
377+
378+
if (this.enumByName.has(property.type.name)) {
379+
const enumeration = this.enumByName.get(property.type.name)!;
380+
381+
if (enumeration.type.name !== "string") {
382+
const enumBaseType = toCppType(enumeration.type);
383+
this.emit(`repr_->emplace("${property.name}", static_cast<${enumBaseType}>(${value}));`);
384+
return true;
385+
}
386+
387+
// TODO: string-like enumeration
388+
return false;
389+
}
390+
391+
if (this.structByName.has(property.type.name)) {
392+
this.emit(`repr_->emplace("${property.name}", ${value});`);
393+
return true;
394+
}
395+
396+
return false;
397+
}
398+
399+
generatePropertySetterOr({
400+
structure,
401+
property,
402+
value,
403+
}: {
404+
structure: Structure;
405+
property: Property;
406+
value: string;
407+
}): boolean {
408+
if (property.type.kind !== "or") return false;
409+
410+
this.emit();
411+
this.emit("// or type");
412+
this.emit();
413+
this.emit(`struct {`);
414+
this.emit(`json* repr_;`);
415+
this.emit();
416+
this.emit(`void operator()(std::monostate) {`);
417+
this.emit(`lsp_runtime_error("monostate is not a valid a property value");`);
418+
this.emit(`}`);
419+
420+
property.type.items.forEach((item) => {
421+
const itemType = this.getPropertyType({ type: item });
422+
this.emit();
423+
this.emit(`void operator()(${itemType} ${property.name}) {`);
424+
this.generatePropertySetter({ property: { name: property.name, type: item, optional: false }, structure });
425+
this.emit(`}`);
426+
});
427+
428+
this.emit(`} v{repr_};`);
429+
this.emit();
430+
this.emit(`std::visit(v, ${value});`);
431+
this.emit();
432+
433+
return true;
434+
}
333435
}
334436

335437
export function gen_types_cc({ model, outputDirectory }: { model: MetaModel; outputDirectory: string }) {

src/lsp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ if (EMSCRIPTEN)
4040
target_compile_options(cxx-lsp PUBLIC -fno-exceptions)
4141
endif()
4242

43+
add_subdirectory(tests)
44+
4345
if(CXX_INSTALL_LSP)
4446

4547
install(

0 commit comments

Comments
 (0)