hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
document.cpp
Go to the documentation of this file.
1//
2// Document Store implementation for hoshi-lang LSP
3//
4
5#include "document.h"
9#include <share/def.hpp>
10#include <atomic>
11#include <filesystem>
12#include <iostream>
13#include <sstream>
14#include <stdexcept>
15
16namespace lsp {
17
19 if (ast) {
21 ast = nullptr;
22 }
23}
24
25void DocumentStore::openDocument(const std::string &uri, const std::string &text,
26 const std::string &languageId, int version) {
27 Document doc;
28 doc.uri = uri;
29 doc.languageId = languageId;
30 doc.version = version;
31 doc.text = yoi::string2wstring(text);
33 documents[uri] = std::move(doc);
34 reparseDocument(uri);
35}
36
37void DocumentStore::updateDocument(const std::string &uri, const std::string &text, int version) {
38 auto it = documents.find(uri);
39 if (it == documents.end()) return;
40
41 it->second.text = yoi::string2wstring(text);
42 it->second.version = version;
43 it->second.projectIndex = projectIndex;
44 reparseDocument(uri);
45}
46
47void DocumentStore::closeDocument(const std::string &uri) {
48 documents.erase(uri);
49}
50
51Document *DocumentStore::getDocument(const std::string &uri) {
52 auto it = documents.find(uri);
53 if (it == documents.end()) return nullptr;
54 return &it->second;
55}
56
57void DocumentStore::reparseDocument(const std::string &uri) {
58 auto it = documents.find(uri);
59 if (it == documents.end()) return;
60
61 Document &doc = it->second;
62
63 // Clean up previous AST
64 if (doc.ast) {
66 doc.ast = nullptr;
67 }
68 doc.symbols.clear();
69 doc.crossModuleSymbols.clear();
70 doc.diagnostics.clear();
71 doc.parseSucceeded = false;
72
73 // Create a diagnostic engine in Collect mode
77
78 // Set current file for error reporting
79 auto savedFilePath = yoi::__current_file_path;
81
82 try {
83 // Lex
84 std::wstringstream stream(doc.text);
85 yoi::lexer lex(std::move(stream));
86 lex.scan();
87
88 // Parse
89 yoi::parse(doc.ast, lex);
90
91 if (doc.ast) {
92 doc.parseSucceeded = true;
93
94 // Collect parse diagnostics now, before the visitor pollutes the engine
95 doc.diagnostics = engine.getDiagnostics();
96 engine.clear();
97
98 // Extract symbols from this document
99 SymbolExtractor extractor;
100 doc.symbols = extractor.extract(doc.ast);
101
102 // Run the visitor in a separate diagnostic scope so its
103 // scope-fallback panics don't become user-facing diagnostics
105 yoi::set_diagnostic_engine(&visitorEngine);
106
107 if (compilerCtx && doc.ast && compilerCtx->getBuildConfig()) {
108 if (!compilerCtx->isInitialized()) {
109 compilerCtx->initializeSharedObjects();
110 }
111 std::string fp = uri;
112 if (fp.rfind("file://", 0) == 0) fp = fp.substr(7);
113 auto &searchPaths = compilerCtx->getBuildConfig()->searchPaths;
114 auto parentPath = std::filesystem::path(fp).parent_path().wstring();
115 searchPaths.push_back(parentPath);
116 searchPaths.push_back((std::filesystem::path(fp).parent_path() / ".tsuki_modules").wstring());
117
118 auto irMod = std::make_shared<yoi::IRModule>();
119 irMod->modulePath = yoi::string2wstring(fp);
120 // Register in moduleImported with a unique index (mirrors compileModule)
121 static std::atomic<yoi::indexT> nextModuleId{1000};
122 yoi::indexT modIdx = nextModuleId++;
123 irMod->identifier = modIdx;
124 compilerCtx->registerModule(modIdx, irMod);
125 auto modCtx = std::make_shared<yoi::moduleContext>(
127 yoi::visitor vis(modCtx, irMod, modIdx);
128 try {
129 vis.visit();
130 } catch (const std::runtime_error &e) {
131 std::cerr << "[lsp] visitor error: " << e.what() << std::endl;
132 }
133
134 searchPaths.pop_back();
135 searchPaths.pop_back();
136 doc.irModule = irMod;
138 }
139
140 // Restore the parse diagnostic engine
142
143 // Resolve and index imported modules
144 resolveAndIndexImports(uri, doc);
145 }
146 } catch (const std::runtime_error &e) {
147 // Parse failed — diagnostics are already in the engine
148 doc.parseSucceeded = false;
149 std::cerr << "[hoshi-lsp] parse failed for " << uri << ": " << e.what() << std::endl;
150 }
151
152 // Collect diagnostics
153 doc.diagnostics = engine.getDiagnostics();
154
155 // Restore state
157 yoi::set_current_file_path(savedFilePath);
158}
159
160void DocumentStore::resolveAndIndexImports(const std::string &uri, Document &doc) {
161 if (!projectIndex || !doc.ast) return;
162
163 // Convert file:// URI to filesystem path
164 std::string filePath = uri;
165 if (filePath.rfind("file://", 0) == 0) {
166 filePath = filePath.substr(7);
167 }
168
169 // Walk the AST to find use and import statements
170 for (auto *stmt : doc.ast->stmts) {
171 if (!stmt) continue;
172
173 std::string importPathStr;
174 yoi::wstr aliasName;
175
176 if (stmt->kind == yoi::globalStmt::vKind::useStmt) {
177 auto *useStmt = static_cast<yoi::useStmt *>(stmt->value.ptr);
178 if (!useStmt) continue;
179 importPathStr = yoi::wstring2string(useStmt->path.strVal);
180 aliasName = useStmt->name->node.strVal;
181 } else if (stmt->kind == yoi::globalStmt::vKind::importDecl) {
182 auto *importStmt = static_cast<yoi::importDecl *>(stmt->value.ptr);
183 if (!importStmt) continue;
184 importPathStr = yoi::wstring2string(importStmt->from_path.strVal);
185 if (importStmt->inner && importStmt->inner->name && importStmt->inner->name->id) {
186 aliasName = importStmt->inner->name->id->node.strVal;
187 }
188 } else {
189 continue;
190 }
191
192 if (importPathStr.empty()) continue;
193
194 // Resolve the module path
195 std::string resolvedPath = projectIndex->resolveModule(importPathStr, filePath);
196 if (resolvedPath.empty()) continue;
197
198 // Index it and get its symbols
199 const auto &modSymbols = projectIndex->indexAndGet(resolvedPath);
200
201 // Tag symbols with module alias and add to crossModuleSymbols
202 for (const auto &sym : modSymbols) {
203 if (sym.isLocal) continue;
204 Symbol tagged = sym;
205 tagged.sourceFile = yoi::string2wstring(resolvedPath);
206 // Set module alias as parent for top-level symbols only.
207 // Symbols that already have a parent (struct methods, etc.)
208 // keep their original parentName so the hierarchy is preserved.
209 if (!aliasName.empty() && tagged.parentName.empty()) {
210 tagged.parentName = aliasName;
211 }
212 doc.crossModuleSymbols.push_back(tagged);
213 }
214 }
215}
216
217} // namespace lsp
void closeDocument(const std::string &uri)
Definition document.cpp:47
void openDocument(const std::string &uri, const std::string &text, const std::string &languageId, int version)
Definition document.cpp:25
void resolveAndIndexImports(const std::string &uri, Document &doc)
Resolve import/use references in the document AST and index referenced modules.
Definition document.cpp:160
void reparseDocument(const std::string &uri)
Definition document.cpp:57
Document * getDocument(const std::string &uri)
Definition document.cpp:51
std::map< std::string, Document > documents
Definition document.h:57
ProjectIndex * projectIndex
Definition document.h:58
std::shared_ptr< yoi::compilerContext > compilerCtx
Definition document.h:59
void updateDocument(const std::string &uri, const std::string &text, int version)
Definition document.cpp:37
const yoi::vec< Symbol > & indexAndGet(const std::string &absolutePath)
Parse and index a module, then return its symbols.
std::string resolveModule(const std::string &importPath, const std::string &relativeToFile)
yoi::vec< Symbol > extract(yoi::hoshiModule *module)
const std::vector< Diagnostic > & getDiagnostics() const
void setCurrentFilePath(const yoi::wstr &path)
Set the file path for diagnostics reported via the convenience overload.
vec< globalStmt * > stmts
Definition ast.hpp:1033
token scan()
Definition lexer.cpp:29
std::shared_ptr< yoi::IRModule > visit()
Definition visitor.cpp:33
std::string wstring2string(const std::wstring &v)
Definition def.cpp:230
std::wstring string2wstring(const std::string &v)
Definition def.cpp:224
thread_local yoi::wstr __current_file_path
Definition def.cpp:15
void set_diagnostic_engine(DiagnosticEngine *engine)
Definition def.cpp:19
void set_current_file_path(const std::wstring &path)
Definition def.cpp:123
void finalizeAST(funcTypeSpec *ptr)
Definition ast.cpp:475
std::wstring wstr
Definition def.hpp:51
uint64_t indexT
Definition def.hpp:54
void parse(yoi::basicLiterals *&o, yoi::lexer &lex)
Definition parser.cpp:25
yoi::vec< Symbol > crossModuleSymbols
Definition document.h:30
yoi::hoshiModule * ast
Definition document.h:28
std::string uri
Definition document.h:24
yoi::vec< Symbol > symbols
Definition document.h:29
yoi::wstr text
Definition document.h:27
ProjectIndex * projectIndex
Definition document.h:33
std::shared_ptr< yoi::compilerContext > compilerCtx
Definition document.h:35
std::string languageId
Definition document.h:25
std::shared_ptr< yoi::IRModule > irModule
Definition document.h:34
yoi::vec< yoi::Diagnostic > diagnostics
Definition document.h:31
bool parseSucceeded
Definition document.h:32
yoi::wstr parentName
yoi::wstr sourceFile