Phasor 3.1.1
Stack VM based Programming Language
Loading...
Searching...
No Matches
LSP.cpp
Go to the documentation of this file.
1#include "LSP.hpp"
2#include <sstream>
3#include <stdexcept>
4
5namespace Phasor
6{
7
8static inline size_t toLexerLine(size_t lspLine)
9{
10 return lspLine + 1;
11}
12static inline size_t toLexerCol(size_t lspCol)
13{
14 return lspCol + 1;
15}
16
17static std::string buildSignature(AST::Node *node)
18{
19 if (auto *fn = dynamic_cast<AST::FunctionDecl *>(node))
20 {
21 std::ostringstream ss;
22 ss << "fn " << fn->name << "(";
23 for (size_t i = 0; i < fn->params.size(); ++i)
24 {
25 if (i)
26 ss << ", ";
27 ss << fn->params[i].name << ": ";
28 if (fn->params[i].type)
29 {
30 ss << fn->params[i].type->name;
31 if (fn->params[i].type->isPointer)
32 ss << "*";
33 for (int dim : fn->params[i].type->arrayDimensions)
34 ss << "[" << dim << "]";
35 }
36 }
37 ss << ")";
38 if (fn->returnType)
39 {
40 ss << " -> " << fn->returnType->name;
41 if (fn->returnType->isPointer)
42 ss << "*";
43 }
44 return ss.str();
45 }
46 if (auto *st = dynamic_cast<AST::StructDecl *>(node))
47 {
48 std::ostringstream ss;
49 ss << "struct " << st->name << " {";
50 for (size_t i = 0; i < st->fields.size(); ++i)
51 {
52 if (i)
53 ss << ", ";
54 ss << " " << st->fields[i].name << ": ";
55 if (st->fields[i].type)
56 {
57 ss << st->fields[i].type->name;
58 if (st->fields[i].type->isPointer)
59 ss << "*";
60 }
61 }
62 ss << " }";
63 return ss.str();
64 }
65 if (auto *vd = dynamic_cast<AST::VarDecl *>(node))
66 return "var " + vd->name;
67
68 return "";
69}
70
71void LSP::openDocument(const std::string &uri, const std::string &text)
72{
73 DocumentState doc;
74 doc.uri = uri;
75 doc.source = text;
76 compile(doc);
77 documents[uri] = std::move(doc);
78}
79
80void LSP::changeDocument(const std::string &uri, const std::string &newText)
81{
82 auto it = documents.find(uri);
83 if (it == documents.end())
84 {
85 openDocument(uri, newText);
86 return;
87 }
88 DocumentState &doc = it->second;
89 doc.source = newText;
90 doc.diagnostics.clear();
91 doc.globalSymbols.clear();
92 doc.program.reset();
93 compile(doc);
94}
95
96void LSP::closeDocument(const std::string &uri)
97{
98 documents.erase(uri);
99}
100
101std::vector<LSP::Diagnostic> LSP::getDiagnostics(const std::string &uri) const
102{
103 auto it = documents.find(uri);
104 if (it == documents.end())
105 return {};
106 return it->second.diagnostics;
107}
108
109AST::Node *LSP::findNodeAtPosition(const std::string &uri, size_t line, size_t column)
110{
111 auto it = documents.find(uri);
112 if (it == documents.end() || !it->second.program)
113 return nullptr;
114 return walkForNode(it->second, toLexerLine(line), toLexerCol(column));
115}
116
117std::optional<std::string> LSP::getHover(const std::string &uri, size_t line, size_t column)
118{
119 auto it = documents.find(uri);
120 if (it == documents.end() || !it->second.program)
121 return std::nullopt;
122
123 const DocumentState &doc = it->second;
124 AST::Node *node = walkForNode(doc, toLexerLine(line), toLexerCol(column));
125 if (!node)
126 return std::nullopt;
127
128 std::string sig = buildSignature(node);
129 if (!sig.empty())
130 return sig;
131
132 std::string name = symbolNameAt(node);
133 if (name.empty())
134 return std::nullopt;
135
136 auto sit = doc.globalSymbols.find(name);
137 if (sit == doc.globalSymbols.end())
138 return std::nullopt;
139
140 return sit->second.signature.empty() ? name : sit->second.signature;
141}
142
143std::optional<LSP::Location> LSP::getDefinition(const std::string &uri, size_t line, size_t column)
144{
145 auto it = documents.find(uri);
146 if (it == documents.end() || !it->second.program)
147 return std::nullopt;
148
149 const DocumentState &doc = it->second;
150 AST::Node *node = walkForNode(doc, toLexerLine(line), toLexerCol(column));
151 if (!node)
152 return std::nullopt;
153
154 std::string name = symbolNameAt(node);
155 if (name.empty())
156 {
157 std::string sig = buildSignature(node);
158 if (!sig.empty() && node->line > 0)
159 {
160 return Location{uri, node->line - 1, node->column > 0 ? node->column - 1 : 0};
161 }
162 return std::nullopt;
163 }
164
165 auto sit = doc.globalSymbols.find(name);
166 if (sit == doc.globalSymbols.end())
167 return std::nullopt;
168
169 AST::Node *decl = sit->second.declaration;
170 if (!decl || decl->line == 0)
171 return std::nullopt;
172
173 return Location{uri, decl->line - 1, decl->column > 0 ? decl->column - 1 : 0};
174}
175
176namespace
177{
178AST::Node *walkStmt(AST::Statement *stmt, size_t line, size_t col);
179AST::Node *walkExpr(AST::Expression *expr, size_t line, size_t col);
180AST::Node *candidate(AST::Node *node, size_t line, size_t col)
181{
182 if (!node || node->line == 0)
183 return nullptr;
184 if (node->line == line && node->column <= col)
185 return node;
186 return nullptr;
187}
188
189AST::Node *walkExpr(AST::Expression *expr, size_t line, size_t col)
190{
191 if (!expr)
192 return nullptr;
193
194 if (auto *e = dynamic_cast<AST::BinaryExpr *>(expr))
195 {
196 if (auto *n = walkExpr(e->left.get(), line, col))
197 return n;
198 if (auto *n = walkExpr(e->right.get(), line, col))
199 return n;
200 }
201 else if (auto *e = dynamic_cast<AST::UnaryExpr *>(expr))
202 {
203 if (auto *n = walkExpr(e->operand.get(), line, col))
204 return n;
205 }
206 else if (auto *e = dynamic_cast<AST::PostfixExpr *>(expr))
207 {
208 if (auto *n = walkExpr(e->operand.get(), line, col))
209 return n;
210 }
211 else if (auto *e = dynamic_cast<AST::AssignmentExpr *>(expr))
212 {
213 if (auto *n = walkExpr(e->target.get(), line, col))
214 return n;
215 if (auto *n = walkExpr(e->value.get(), line, col))
216 return n;
217 }
218 else if (auto *e = dynamic_cast<AST::CallExpr *>(expr))
219 {
220 for (const auto &arg : e->arguments)
221 if (auto *n = walkExpr(arg.get(), line, col))
222 return n;
223 }
224 else if (auto *e = dynamic_cast<AST::ArrayAccessExpr *>(expr))
225 {
226 if (auto *n = walkExpr(e->array.get(), line, col))
227 return n;
228 if (auto *n = walkExpr(e->index.get(), line, col))
229 return n;
230 }
231 else if (auto *e = dynamic_cast<AST::ArrayLiteralExpr *>(expr))
232 {
233 for (const auto &elem : e->elements)
234 if (auto *n = walkExpr(elem.get(), line, col))
235 return n;
236 }
237 else if (auto *e = dynamic_cast<AST::MemberAccessExpr *>(expr))
238 {
239 if (auto *n = walkExpr(e->object.get(), line, col))
240 return n;
241 }
242 else if (auto *e = dynamic_cast<AST::FieldAccessExpr *>(expr))
243 {
244 if (auto *n = walkExpr(e->object.get(), line, col))
245 return n;
246 }
247 else if (auto *e = dynamic_cast<AST::StructInstanceExpr *>(expr))
248 {
249 for (const auto &fv : e->fieldValues)
250 if (auto *n = walkExpr(fv.second.get(), line, col))
251 return n;
252 }
253
254 return candidate(expr, line, col);
255}
256
257AST::Node *walkStmt(AST::Statement *stmt, size_t line, size_t col)
258{
259 if (!stmt)
260 return nullptr;
261
262 if (auto *s = dynamic_cast<AST::BlockStmt *>(stmt))
263 {
264 for (const auto &child : s->statements)
265 if (auto *n = walkStmt(child.get(), line, col))
266 return n;
267 }
268 else if (auto *s = dynamic_cast<AST::ExpressionStmt *>(stmt))
269 {
270 if (auto *n = walkExpr(s->expression.get(), line, col))
271 return n;
272 }
273 else if (auto *s = dynamic_cast<AST::PrintStmt *>(stmt))
274 {
275 if (auto *n = walkExpr(s->expression.get(), line, col))
276 return n;
277 }
278 else if (auto *s = dynamic_cast<AST::VarDecl *>(stmt))
279 {
280 if (auto *n = walkExpr(s->initializer.get(), line, col))
281 return n;
282 return candidate(s, line, col);
283 }
284 else if (auto *s = dynamic_cast<AST::ReturnStmt *>(stmt))
285 {
286 if (auto *n = walkExpr(s->value.get(), line, col))
287 return n;
288 }
289 else if (auto *s = dynamic_cast<AST::IfStmt *>(stmt))
290 {
291 if (auto *n = walkExpr(s->condition.get(), line, col))
292 return n;
293 if (auto *n = walkStmt(s->thenBranch.get(), line, col))
294 return n;
295 if (auto *n = walkStmt(s->elseBranch.get(), line, col))
296 return n;
297 }
298 else if (auto *s = dynamic_cast<AST::WhileStmt *>(stmt))
299 {
300 if (auto *n = walkExpr(s->condition.get(), line, col))
301 return n;
302 if (auto *n = walkStmt(s->body.get(), line, col))
303 return n;
304 }
305 else if (auto *s = dynamic_cast<AST::ForStmt *>(stmt))
306 {
307 if (auto *n = walkStmt(s->initializer.get(), line, col))
308 return n;
309 if (auto *n = walkExpr(s->condition.get(), line, col))
310 return n;
311 if (auto *n = walkExpr(s->increment.get(), line, col))
312 return n;
313 if (auto *n = walkStmt(s->body.get(), line, col))
314 return n;
315 }
316 else if (auto *s = dynamic_cast<AST::SwitchStmt *>(stmt))
317 {
318 if (auto *n = walkExpr(s->expr.get(), line, col))
319 return n;
320 for (const auto &c : s->cases)
321 {
322 if (auto *n = walkExpr(c.value.get(), line, col))
323 return n;
324 for (const auto &cs : c.statements)
325 if (auto *n = walkStmt(cs.get(), line, col))
326 return n;
327 }
328 for (const auto &ds : s->defaultStmts)
329 if (auto *n = walkStmt(ds.get(), line, col))
330 return n;
331 }
332 else if (auto *s = dynamic_cast<AST::FunctionDecl *>(stmt))
333 {
334 if (s->body)
335 if (auto *n = walkStmt(s->body.get(), line, col))
336 return n;
337 return candidate(s, line, col);
338 }
339 else if (auto *s = dynamic_cast<AST::StructDecl *>(stmt))
340 {
341 return candidate(s, line, col);
342 }
343 else if (auto *s = dynamic_cast<AST::ExportStmt *>(stmt))
344 {
345 if (auto *n = walkStmt(s->declaration.get(), line, col))
346 return n;
347 }
348 else if (auto *s = dynamic_cast<AST::UnsafeBlockStmt *>(stmt))
349 {
350 if (auto *n = walkStmt(s->block.get(), line, col))
351 return n;
352 }
353
354 return candidate(stmt, line, col);
355}
356}
357
358AST::Node *LSP::walkForNode(const DocumentState &doc, size_t line, size_t col)
359{
360 if (!doc.program)
361 return nullptr;
362 for (const auto &stmt : doc.program->statements)
363 if (auto *n = walkStmt(stmt.get(), line, col))
364 return n;
365 return nullptr;
366}
367
368std::string LSP::symbolNameAt(AST::Node *node) const
369{
370 if (!node)
371 return "";
372 if (auto *e = dynamic_cast<AST::IdentifierExpr *>(node))
373 return e->name;
374 if (auto *e = dynamic_cast<AST::CallExpr *>(node))
375 return e->callee;
376 if (auto *e = dynamic_cast<AST::StructInstanceExpr *>(node))
377 return e->structName;
378 if (auto *e = dynamic_cast<AST::FieldAccessExpr *>(node))
379 return e->fieldName;
380 if (auto *e = dynamic_cast<AST::MemberAccessExpr *>(node))
381 return e->member;
382 return "";
383}
384
386{
387 doc.lineStartOffsets.clear();
388 doc.lineStartOffsets.push_back(0);
389 for (size_t i = 0; i < doc.source.size(); ++i)
390 if (doc.source[i] == '\n')
391 doc.lineStartOffsets.push_back(i + 1);
392}
393
395{
396 if (!doc.program)
397 return;
398
399 auto tryRegister = [&](const std::string &name, AST::Node *node) {
400 SymbolInfo info;
401 info.name = name;
402 info.declaration = node;
403 info.signature = buildSignature(node);
404 doc.globalSymbols[name] = std::move(info);
405 };
406
407 for (const auto &stmt : doc.program->statements)
408 {
409 if (auto *fn = dynamic_cast<AST::FunctionDecl *>(stmt.get()))
410 tryRegister(fn->name, fn);
411 else if (auto *st = dynamic_cast<AST::StructDecl *>(stmt.get()))
412 tryRegister(st->name, st);
413 else if (auto *vd = dynamic_cast<AST::VarDecl *>(stmt.get()))
414 tryRegister(vd->name, vd);
415 else if (auto *ex = dynamic_cast<AST::ExportStmt *>(stmt.get()))
416 {
417 if (auto *fn = dynamic_cast<AST::FunctionDecl *>(ex->declaration.get()))
418 tryRegister(fn->name, fn);
419 else if (auto *st = dynamic_cast<AST::StructDecl *>(ex->declaration.get()))
420 tryRegister(st->name, st);
421 else if (auto *vd = dynamic_cast<AST::VarDecl *>(ex->declaration.get()))
422 tryRegister(vd->name, vd);
423 }
424 }
425}
426
428{
430 try
431 {
432 Lexer lexer(doc.source);
433 auto tokens = lexer.tokenize();
434 Parser parser(tokens);
435 doc.program = parser.parse();
436
437 if (auto err = lexer.getError())
438 {
439 doc.diagnostics.push_back({err->message, err->line, err->column, err->line, err->column + 1});
440 return;
441 }
442
443 if (auto err = parser.getError())
444 {
445 doc.diagnostics.push_back({err->message, err->line, err->column, err->line, err->column + 1});
446 doc.program.reset();
447 return;
448 }
449 }
450 catch (const std::runtime_error &e)
451 {
452 std::cerr << e.what();
453 }
454 catch (...)
455 {
456 std::cerr << "Caught unknown exception";
457 }
459}
460
461} // namespace Phasor
AST::Node * walkForNode(const DocumentState &doc, size_t line, size_t col)
Definition LSP.cpp:358
std::optional< Location > getDefinition(const std::string &uri, size_t line, size_t column)
Definition LSP.cpp:143
void buildGlobalSymbols(DocumentState &doc)
Definition LSP.cpp:394
void openDocument(const std::string &uri, const std::string &text)
Definition LSP.cpp:71
void closeDocument(const std::string &uri)
Definition LSP.cpp:96
AST::Node * findNodeAtPosition(const std::string &uri, size_t line, size_t column)
Definition LSP.cpp:109
void compile(DocumentState &doc)
Definition LSP.cpp:427
std::vector< Diagnostic > getDiagnostics(const std::string &uri) const
Definition LSP.cpp:101
std::string symbolNameAt(AST::Node *node) const
Definition LSP.cpp:368
std::optional< std::string > getHover(const std::string &uri, size_t line, size_t column)
Definition LSP.cpp:117
void changeDocument(const std::string &uri, const std::string &newText)
Definition LSP.cpp:80
std::unordered_map< std::string, DocumentState > documents
Definition LSP.hpp:66
void computeLineOffsets(DocumentState &doc)
Definition LSP.cpp:385
Lexer.
Definition Lexer.hpp:13
std::vector< Token > tokenize()
Definition Lexer.cpp:26
std::optional< Error > getError() const
Definition Lexer.hpp:25
Parser.
Definition Parser.hpp:13
std::unique_ptr< AST::Program > parse()
Definition Parser.cpp:73
std::optional< Error > getError() const
Definition Parser.hpp:31
The Phasor Programming Language and Runtime.
Definition AST.hpp:11
static std::string buildSignature(AST::Node *node)
Definition LSP.cpp:17
static size_t toLexerLine(size_t lspLine)
Definition LSP.cpp:8
static size_t toLexerCol(size_t lspCol)
Definition LSP.cpp:12
Array Access Expression Node.
Definition AST.hpp:313
Array Literal Expression Node.
Definition AST.hpp:333
Assignment Expression Node.
Definition AST.hpp:385
Block Statement Node.
Definition AST.hpp:489
Call Expression Node.
Definition AST.hpp:365
Export Statement Node.
Definition AST.hpp:475
Expression Node.
Definition AST.hpp:53
Expression Statement Node.
Definition AST.hpp:422
Field Access Expression Node.
Definition AST.hpp:714
For Statement Node.
Definition AST.hpp:583
Function Declaration Node.
Definition AST.hpp:624
Identifier Expression Node.
Definition AST.hpp:124
If Statement Node.
Definition AST.hpp:539
Member Access Expression Node.
Definition AST.hpp:348
AST Node.
Definition AST.hpp:44
size_t line
Definition AST.hpp:47
size_t column
Definition AST.hpp:48
Postfix Expression Node.
Definition AST.hpp:193
Print Statement Node.
Definition AST.hpp:435
Return Statement Node.
Definition AST.hpp:506
Statement Node.
Definition AST.hpp:58
Struct Declaration Node.
Definition AST.hpp:671
Struct Instance Expression Node.
Definition AST.hpp:692
Switch Statement Node.
Definition AST.hpp:744
Unary Expression Node.
Definition AST.hpp:219
Unsafe Block Statement Node.
Definition AST.hpp:610
Variable Declaration Node.
Definition AST.hpp:406
While Statement Node.
Definition AST.hpp:564
std::unordered_map< std::string, SymbolInfo > globalSymbols
Definition LSP.hpp:47
std::vector< size_t > lineStartOffsets
Definition LSP.hpp:44
std::unique_ptr< AST::Program > program
Definition LSP.hpp:45
std::vector< Diagnostic > diagnostics
Definition LSP.hpp:46
std::string signature
Definition LSP.hpp:30
AST::Node * declaration
Definition LSP.hpp:29
std::string name
Definition LSP.hpp:28