#include "slang-wasm.h" #include "../core/slang-blob.h" #include "../core/slang-exception.h" #include "../slang/slang-language-server.h" #include #include using namespace slang; namespace slang { namespace wgsl { Error g_error; Error getLastError() { Error currentError = g_error; g_error = {}; return currentError; } emscripten::val getCompileTargets() { struct TargetPair { const char* name; SlangCompileTarget target; }; static const TargetPair targets[] = { {"GLSL", SLANG_GLSL}, {"HLSL", SLANG_HLSL}, {"WGSL", SLANG_WGSL}, {"SPIRV", SLANG_SPIRV}, {"METAL", SLANG_METAL}, {"CUDA", SLANG_CUDA_SOURCE}, }; std::vector result; for (auto target : targets) { auto entry = emscripten::val::object(); entry.set("name", target.name); entry.set("value", (int)target.target); result.push_back(entry); } return emscripten::val::array(result); } GlobalSession* createGlobalSession() { IGlobalSession* globalSession = nullptr; { SlangResult result = slang::createGlobalSession(&globalSession); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; return nullptr; } } return new GlobalSession(globalSession); } Session* GlobalSession::createSession(int compileTarget) { Slang::ComPtr session; { SessionDesc sessionDesc = {}; sessionDesc.structureSize = sizeof(sessionDesc); constexpr SlangInt targetCount = 1; TargetDesc target = {}; target.format = (SlangCompileTarget)compileTarget; if (compileTarget == SLANG_HLSL) { target.profile = spFindProfile(m_interface, "sm_6_6"); } sessionDesc.targets = ⌖ sessionDesc.targetCount = targetCount; SlangResult result = m_interface->createSession(sessionDesc, session.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; return nullptr; } } return new Session(session); } Session::~Session() { m_componentTypes = {}; auto refCount = static_cast(m_interface.get())->debugGetReferenceCount(); m_interface = nullptr; } emscripten::val Session::loadModuleFromSource( const std::string& slangCode, const std::string& name, const std::string& path) { IModule* module = nullptr; { Slang::ComPtr diagnosticsBlob; Slang::ComPtr slangCodeBlob = Slang::RawBlob::create(slangCode.c_str(), slangCode.size()); module = m_interface->loadModuleFromSource( name.c_str(), path.c_str(), slangCodeBlob, diagnosticsBlob.writeRef()); if (!module) { g_error.type = std::string("USER"); g_error.message = std::string( (char*)diagnosticsBlob->getBufferPointer(), (char*)diagnosticsBlob->getBufferPointer() + diagnosticsBlob->getBufferSize()); return emscripten::val::null(); } } return emscripten::val(Module(module, this)); } emscripten::val Module::findEntryPointByName(const std::string& name) { Slang::ComPtr entryPoint; { SlangResult result = moduleInterface()->findEntryPointByName(name.c_str(), entryPoint.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; return emscripten::val::null(); } } m_session->addComponentType(entryPoint.get()); return emscripten::val(EntryPoint(entryPoint.get(), m_session)); } emscripten::val Module::findAndCheckEntryPoint(const std::string& name, int stage) { Slang::ComPtr entryPoint; { Slang::ComPtr diagnosticsBlob; SlangResult result = moduleInterface()->findAndCheckEntryPoint( name.c_str(), (SlangStage)stage, entryPoint.writeRef(), diagnosticsBlob.writeRef()); if (!SLANG_SUCCEEDED(result)) { g_error.type = std::string("USER"); g_error.result = result; if (diagnosticsBlob->getBufferSize()) { char* diagnostics = (char*)diagnosticsBlob->getBufferPointer(); g_error.message = std::string(diagnostics); } return emscripten::val::null(); } } m_session->addComponentType(entryPoint.get()); return emscripten::val(EntryPoint(entryPoint.get(), m_session)); } int Module::getDefinedEntryPointCount() { return moduleInterface()->getDefinedEntryPointCount(); } emscripten::val Module::getDefinedEntryPoint(int index) { if (moduleInterface()->getDefinedEntryPointCount() <= index) return emscripten::val::null(); Slang::ComPtr entryPoint; { Slang::ComPtr diagnosticsBlob; SlangResult result = moduleInterface()->getDefinedEntryPoint(index, entryPoint.writeRef()); if (!SLANG_SUCCEEDED(result)) { g_error.type = std::string("USER"); g_error.result = result; if (diagnosticsBlob->getBufferSize()) { char* diagnostics = (char*)diagnosticsBlob->getBufferPointer(); g_error.message = std::string(diagnostics); } return emscripten::val::null(); } } m_session->addComponentType(entryPoint.get()); return emscripten::val(EntryPoint(entryPoint.get(), m_session)); } emscripten::val Session::createCompositeComponentType(emscripten::val components) { if (!components.isArray()) { g_error.type = std::string("Slang WASM Bind"); g_error.message = std::string("createCompositeComponentType: Components must be an array"); return emscripten::val::null(); } std::vector componentsArray = emscripten::vecFromJSArray(components); Slang::ComPtr composite; { std::vector nativeComponents; for (size_t i = 0U; i < componentsArray.size(); i++) { auto componentVal = componentsArray[i]; if (componentVal.instanceof (emscripten::val::module_property("ComponentType"))) { auto componentType = componentVal.as(); nativeComponents.push_back(componentType.interface()); } } SlangResult result = m_interface->createCompositeComponentType( nativeComponents.data(), (SlangInt)nativeComponents.size(), composite.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; return emscripten::val::null(); } } addComponentType(composite.get()); return emscripten::val(ComponentType(composite, this)); } emscripten::val ComponentType::link() { Slang::ComPtr linkedProgram; { Slang::ComPtr diagnosticBlob; SlangResult result = interface()->link(linkedProgram.writeRef(), diagnosticBlob.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; g_error.message = std::string( (char*)diagnosticBlob->getBufferPointer(), (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize()); return emscripten::val::null(); } } m_session->addComponentType(linkedProgram.get()); return emscripten::val(ComponentType(linkedProgram, m_session)); } std::string ComponentType::getEntryPointCode(int entryPointIndex, int targetIndex) { { Slang::ComPtr kernelBlob; Slang::ComPtr diagnosticBlob; SlangResult result = interface()->getEntryPointCode( entryPointIndex, targetIndex, kernelBlob.writeRef(), diagnosticBlob.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; g_error.message = std::string( (char*)diagnosticBlob->getBufferPointer(), (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize()); return ""; } std::string wgslCode = std::string( (char*)kernelBlob->getBufferPointer(), (char*)kernelBlob->getBufferPointer() + kernelBlob->getBufferSize()); return wgslCode; } return {}; } // Since result code is binary, we can't return it as a string, we will need to use emscripten::val // to wrap it and return it to the javascript side. emscripten::val ComponentType::getEntryPointCodeBlob(int entryPointIndex, int targetIndex) { Slang::ComPtr kernelBlob; Slang::ComPtr diagnosticBlob; SlangResult result = interface()->getEntryPointCode( entryPointIndex, targetIndex, kernelBlob.writeRef(), diagnosticBlob.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; g_error.message = std::string( (char*)diagnosticBlob->getBufferPointer(), (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize()); return {}; } const uint8_t* ptr = (uint8_t*)kernelBlob->getBufferPointer(); return emscripten::val(emscripten::typed_memory_view(kernelBlob->getBufferSize(), ptr)); } std::string ComponentType::getTargetCode(int targetIndex) { { Slang::ComPtr kernelBlob; Slang::ComPtr diagnosticBlob; SlangResult result = interface()->getTargetCode( targetIndex, kernelBlob.writeRef(), diagnosticBlob.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; g_error.message = std::string( (char*)diagnosticBlob->getBufferPointer(), (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize()); return ""; } std::string targetCode = std::string( (char*)kernelBlob->getBufferPointer(), (char*)kernelBlob->getBufferPointer() + kernelBlob->getBufferSize()); return targetCode; } return {}; } // Since result code is binary, we can't return it as a string, we will need to use emscripten::val // to wrap it and return it to the javascript side. emscripten::val ComponentType::getTargetCodeBlob(int targetIndex) { Slang::ComPtr kernelBlob; Slang::ComPtr diagnosticBlob; SlangResult result = interface()->getTargetCode(targetIndex, kernelBlob.writeRef(), diagnosticBlob.writeRef()); if (result != SLANG_OK) { g_error.type = std::string("USER"); g_error.result = result; g_error.message = std::string( (char*)diagnosticBlob->getBufferPointer(), (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize()); return {}; } const uint8_t* ptr = (uint8_t*)kernelBlob->getBufferPointer(); return emscripten::val(emscripten::typed_memory_view(kernelBlob->getBufferSize(), ptr)); } emscripten::val ComponentType::loadStrings() { slang::ProgramLayout* slangReflection = interface()->getLayout(); if (!slangReflection) { g_error.type = std::string("USER"); g_error.message = std::string("Failed to get reflection data"); return emscripten::val::null(); } SlangUInt hashedStringCount = slangReflection->getHashedStringCount(); if (hashedStringCount == 0) { g_error.type = std::string("USER"); g_error.message = std::string("Warn: No reflection data found"); return emscripten::val::null(); } size_t stringSize = 0; std::vector result; for (SlangUInt ii = 0; ii < hashedStringCount; ++ii) { // For each string we can fetch its bytes from the Slang // reflection data. // size_t stringSize = 0; char const* stringData = slangReflection->getHashedString(ii, &stringSize); // Then we can compute the hash code for that string using // another Slang API function. // // Note: the exact hashing algorithm that Slang uses for // string literals is not currently documented, and may // change in future releases of the compiler. // int hash = spComputeStringHash(stringData, stringSize); emscripten::val entry = emscripten::val::object(); entry.set("hash", hash); entry.set("string", std::string(stringData)); result.push_back(entry); } return emscripten::val::array(result); } ProgramLayout* ComponentType::getLayout(uint32_t targetIndex) { return (slang::wgsl::ProgramLayout*)interface()->getLayout(targetIndex); } uint32_t ProgramLayout::getParameterCount() { return interface()->getParameterCount(); } emscripten::val ProgramLayout::toJsonObject() { Slang::ComPtr blob; if (SLANG_FAILED(interface()->toJson(blob.writeRef()))) return {}; auto jsonString = std::string( (char*)blob->getBufferPointer(), (char*)blob->getBufferPointer() + blob->getBufferSize()); emscripten::val parsedObject = emscripten::val::global("JSON").call("parse", jsonString); return parsedObject; } VariableLayoutReflection* ProgramLayout::getParameterByIndex(uint32_t index) { return (slang::wgsl::VariableLayoutReflection*)(interface()->getParameterByIndex(index)); } TypeLayoutReflection* ProgramLayout::getGlobalParamsTypeLayout() { return (slang::wgsl::TypeLayoutReflection*)(interface()->getGlobalParamsTypeLayout()); } FunctionReflection* ProgramLayout::findFunctionByName(std::string name) { return (slang::wgsl::FunctionReflection*)(interface()->findFunctionByName(name.c_str())); } EntryPointReflection* ProgramLayout::findEntryPointByName(std::string name) { return (slang::wgsl::EntryPointReflection*)(interface()->findEntryPointByName(name.c_str())); } EntryPointReflection::ThreadGroupSize EntryPointReflection::getComputeThreadGroupSize() { SlangUInt size[3]; interface()->getComputeThreadGroupSize(3, size); return {size[0], size[1], size[2]}; } BindingType TypeLayoutReflection::getDescriptorSetDescriptorRangeType( uint32_t setIndex, uint32_t rangeIndex) { return interface()->getDescriptorSetDescriptorRangeType(setIndex, rangeIndex); } std::string DeclReflection::getName() { return interface()->getName(); } slang::DeclReflection::Kind DeclReflection::getKind() { return interface()->getKind(); } uint32_t DeclReflection::getChildrenCount() { return interface()->getChildrenCount(); }; slang::wgsl::DeclReflection* DeclReflection::getChild(uint32_t index) { return (slang::wgsl::DeclReflection*)interface()->getChild(index); } slang::wgsl::TypeReflection* DeclReflection::getType() { return (slang::wgsl::TypeReflection*)interface()->getType(); } slang::wgsl::VariableReflection* DeclReflection::asVariable() { return (slang::wgsl::VariableReflection*)interface()->asVariable(); } slang::wgsl::FunctionReflection* DeclReflection::asFunction() { return (slang::wgsl::FunctionReflection*)interface()->asFunction(); } slang::wgsl::GenericReflection* DeclReflection::asGeneric() { return (slang::wgsl::GenericReflection*)interface()->asGeneric(); } slang::wgsl::DeclReflection* DeclReflection::getParent() { return (slang::wgsl::DeclReflection*)interface()->getParent(); } std::string GenericReflection::getName() { return interface()->getName(); } slang::wgsl::DeclReflection* GenericReflection::asDecl() { return (slang::wgsl::DeclReflection*)interface()->asDecl(); } uint32_t GenericReflection::getTypeParameterCount() { return interface()->getTypeParameterCount(); } slang::wgsl::VariableReflection* GenericReflection::getTypeParameter(unsigned index) { return (slang::wgsl::VariableReflection*)interface()->getTypeParameter(index); } uint32_t GenericReflection::getValueParameterCount() { return interface()->getValueParameterCount(); } slang::wgsl::VariableReflection* GenericReflection::getValueParameter(unsigned index) { return (slang::wgsl::VariableReflection*)interface()->getValueParameter(index); } slang::wgsl::DeclReflection* GenericReflection::getInnerDecl() { return (slang::wgsl::DeclReflection*)interface()->getInnerDecl(); } SlangDeclKind GenericReflection::getInnerKind() { return interface()->getInnerKind(); } slang::wgsl::GenericReflection* GenericReflection::getOuterGenericContainer() { return (slang::wgsl::GenericReflection*)interface()->getOuterGenericContainer(); } std::string VariableLayoutReflection::getName() { return interface()->getName(); } slang::wgsl::TypeLayoutReflection* VariableLayoutReflection::getTypeLayout() { return (slang::wgsl::TypeLayoutReflection*)(interface()->getTypeLayout()); } uint32_t VariableLayoutReflection::getBindingIndex() { return interface()->getBindingIndex(); } std::string VariableReflection::getName() { return interface()->getName(); } uint32_t VariableReflection::getUserAttributeCount() { return interface()->getUserAttributeCount(); } slang::wgsl::UserAttribute* VariableReflection::getUserAttributeByIndex(uint32_t index) { return (slang::wgsl::UserAttribute*)interface()->getUserAttributeByIndex(index); } bool VariableReflection::hasDefaultValue() { return interface()->hasDefaultValue(); } slang::wgsl::TypeReflection* VariableReflection::getType() { return (slang::wgsl::TypeReflection*)interface()->getType(); } Modifier* VariableReflection::findModifier(Modifier::ID id) { return interface()->findModifier(id); } slang::wgsl::VariableReflection* TypeReflection::getFieldByIndex(uint32_t index) { return (slang::wgsl::VariableReflection*)interface()->getFieldByIndex(index); } slang::TypeReflection::ScalarType TypeReflection::getScalarType() { return interface()->getScalarType(); } slang::TypeReflection::Kind TypeReflection::getKind() { return interface()->getKind(); } std::string UserAttribute::getName() { return interface()->getName(); } float UserAttribute::getArgumentValueFloat(uint32_t index) { float value; interface()->getArgumentValueFloat(index, &value); return value; } std::string UserAttribute::getArgumentValueString(uint32_t index) { size_t len = 0; const char* out = interface()->getArgumentValueString(index, &len); return std::string(out, len); } slang::wgsl::TypeReflection* UserAttribute::getArgumentType(uint32_t index) { return (slang::wgsl::TypeReflection*)interface()->getArgumentType(index); } uint32_t UserAttribute::getArgumentCount() { return interface()->getArgumentCount(); } std::string FunctionReflection::getName() { return interface()->getName(); } uint32_t FunctionReflection::getUserAttributeCount() { return interface()->getUserAttributeCount(); } slang::wgsl::UserAttribute* FunctionReflection::getUserAttributeByIndex(uint32_t index) { return (slang::wgsl::UserAttribute*)interface()->getUserAttributeByIndex(index); } namespace lsp { Position translate(Slang::LanguageServerProtocol::Position p) { Position result; result.line = p.line; result.character = p.character; return result; } Range translate(Slang::LanguageServerProtocol::Range r) { Range result; result.start = translate(r.start); result.end = translate(r.end); return result; } Location translate(Slang::LanguageServerProtocol::Location l) { Location result; result.uri = l.uri.getBuffer(); result.range = translate(l.range); return result; } Slang::LanguageServerProtocol::Position translate(Position p) { Slang::LanguageServerProtocol::Position result; result.line = p.line; result.character = p.character; return result; } Slang::LanguageServerProtocol::Range translate(Range r) { Slang::LanguageServerProtocol::Range result; result.start = translate(r.start); result.end = translate(r.end); return result; } Slang::LanguageServerProtocol::Location translate(Location l) { Slang::LanguageServerProtocol::Location result; result.uri = l.uri.c_str(); result.range = translate(l.range); return result; } LanguageServer::LanguageServer() { Slang::LanguageServerStartupOptions options = {}; m_core = new Slang::LanguageServerCore(options); init(); } LanguageServer::~LanguageServer() { delete m_core; } void LanguageServer::init() { Slang::LanguageServerProtocol::InitializeParams args = {}; Slang::LanguageServerProtocol::WorkspaceFolder folder = {}; folder.uri = "file:///"; folder.name = "/"; args.workspaceFolders.add(folder); m_core->init(args); } void LanguageServer::didOpenTextDocument(std::string uri, std::string text) { Slang::LanguageServerProtocol::DidOpenTextDocumentParams args = {}; args.textDocument.uri = uri.c_str(); args.textDocument.languageId = "slang"; args.textDocument.text = text.c_str(); m_core->didOpenTextDocument(args); } void LanguageServer::didCloseTextDocument(std::string uri) { Slang::LanguageServerProtocol::DidCloseTextDocumentParams args = {}; args.textDocument.uri = uri.c_str(); m_core->didCloseTextDocument(args); } void LanguageServer::didChangeTextDocument( std::string uri, const std::vector& changes) { Slang::LanguageServerProtocol::DidChangeTextDocumentParams args = {}; args.textDocument.uri = uri.c_str(); for (auto change : changes) { Slang::LanguageServerProtocol::TextDocumentContentChangeEvent lspChange; lspChange.text = change.text.c_str(); lspChange.range = translate(change.range); args.contentChanges.add(lspChange); } m_core->didChangeTextDocument(args); } std::optional LanguageServer::hover(std::string uri, lsp::Position position) { Slang::LanguageServerProtocol::HoverParams args = {}; args.textDocument.uri = uri.c_str(); args.position = translate(position); auto coreResult = m_core->hover(args); if (coreResult.isNull) return std::nullopt; lsp::Hover result; result.contents.kind = coreResult.result.contents.kind.getBuffer(); result.contents.value = coreResult.result.contents.value.getBuffer(); result.range = translate(coreResult.result.range); return result; } std::optional> LanguageServer::gotoDefinition( std::string uri, lsp::Position position) { Slang::LanguageServerProtocol::DefinitionParams args = {}; args.textDocument.uri = uri.c_str(); args.position = translate(position); auto coreResult = m_core->gotoDefinition(args); if (coreResult.isNull) return std::nullopt; std::vector result; for (auto location : coreResult.result) result.push_back(translate(location)); return result; } std::optional> LanguageServer::completion( std::string uri, lsp::Position position, CompletionContext context) { Slang::LanguageServerProtocol::CompletionParams args = {}; args.textDocument.uri = uri.c_str(); args.position = translate(position); args.context.triggerKind = context.triggerKind; args.context.triggerCharacter = context.triggerCharacter.c_str(); auto coreResult = m_core->completion(args); if (coreResult.isNull) return std::nullopt; std::vector result; for (auto item : coreResult.result.items) { lsp::CompletionItem completionItem; completionItem.label = item.label.getBuffer(); completionItem.kind = item.kind; completionItem.detail = item.detail.getBuffer(); MarkupContent documentation; documentation.kind = item.documentation.kind.getBuffer(); documentation.value = item.documentation.value.getBuffer(); completionItem.documentation = documentation; completionItem.textEdit = std::nullopt; completionItem.data = item.data.getBuffer(); std::vector commitCharacters; for (auto character : item.commitCharacters) commitCharacters.push_back(character.getBuffer()); completionItem.commitCharacters = commitCharacters; result.push_back(completionItem); } return result; } std::optional LanguageServer::completionResolve(lsp::CompletionItem args) { Slang::LanguageServerProtocol::CompletionItem coreArgs = {}; coreArgs.label = args.label.c_str(); coreArgs.kind = args.kind; coreArgs.detail = args.detail.c_str(); if (args.documentation.has_value()) { coreArgs.documentation.kind = args.documentation.value().kind.c_str(); coreArgs.documentation.value = args.documentation.value().value.c_str(); } coreArgs.data = args.data.c_str(); if (args.commitCharacters.has_value()) { for (auto character : args.commitCharacters.value()) coreArgs.commitCharacters.add(character.c_str()); } Slang::LanguageServerProtocol::TextEditCompletionItem editItem; editItem.label = coreArgs.label; editItem.kind = coreArgs.kind; editItem.detail = coreArgs.detail; editItem.documentation.kind = coreArgs.documentation.kind; editItem.documentation.value = coreArgs.documentation.value; editItem.data = coreArgs.data; for (auto character : coreArgs.commitCharacters) editItem.commitCharacters.add(character); auto coreResult = m_core->completionResolve(coreArgs, editItem); if (coreResult.isNull) return std::nullopt; lsp::CompletionItem result; result.label = coreResult.result.label.getBuffer(); result.kind = coreResult.result.kind; result.detail = coreResult.result.detail.getBuffer(); MarkupContent documentation; documentation.kind = coreResult.result.documentation.kind.getBuffer(); documentation.value = coreResult.result.documentation.value.getBuffer(); result.documentation = documentation; result.textEdit = std::nullopt; result.data = coreResult.result.data.getBuffer(); std::vector commitCharacters; for (auto character : coreResult.result.commitCharacters) commitCharacters.push_back(character.getBuffer()); result.commitCharacters = commitCharacters; return result; } std::optional> LanguageServer::semanticTokens(std::string uri) { Slang::LanguageServerProtocol::SemanticTokensParams args = {}; args.textDocument.uri = uri.c_str(); auto coreResult = m_core->semanticTokens(args); if (coreResult.isNull) return std::nullopt; std::vector result; result.reserve((size_t)coreResult.result.data.getCount()); for (auto token : coreResult.result.data) result.push_back(token); return result; } std::optional LanguageServer::signatureHelp( std::string uri, lsp::Position position) { Slang::LanguageServerProtocol::SignatureHelpParams args = {}; args.textDocument.uri = uri.c_str(); args.position = translate(position); auto coreResult = m_core->signatureHelp(args); if (coreResult.isNull) return std::nullopt; lsp::SignatureHelp result; for (auto signature : coreResult.result.signatures) { lsp::SignatureInformation signatureInfo; signatureInfo.label = signature.label.getBuffer(); signatureInfo.documentation.kind = signature.documentation.kind.getBuffer(); signatureInfo.documentation.value = signature.documentation.value.getBuffer(); for (auto parameter : signature.parameters) { lsp::ParameterInformation parameterInfo; parameterInfo.label[0] = parameter.label[0]; parameterInfo.label[1] = parameter.label[1]; parameterInfo.documentation.kind = parameter.documentation.kind.getBuffer(); parameterInfo.documentation.value = parameter.documentation.value.getBuffer(); signatureInfo.parameters.push_back(parameterInfo); } result.signatures.push_back(signatureInfo); } result.activeSignature = coreResult.result.activeSignature; result.activeParameter = coreResult.result.activeParameter; return result; } lsp::DocumentSymbol translate(Slang::LanguageServerProtocol::DocumentSymbol symbol) { lsp::DocumentSymbol result; result.name = symbol.name.getBuffer(); result.detail = symbol.detail.getBuffer(); result.kind = symbol.kind; result.range = translate(symbol.range); result.selectionRange = translate(symbol.selectionRange); for (auto child : symbol.children) result.children.push_back(translate(child)); return result; } std::optional> LanguageServer::documentSymbol(std::string uri) { Slang::LanguageServerProtocol::DocumentSymbolParams args = {}; args.textDocument.uri = uri.c_str(); auto coreResult = m_core->documentSymbol(args); if (coreResult.isNull) return std::nullopt; std::vector result; for (auto symbol : coreResult.result) { auto documentSymbol = translate(symbol); result.push_back(documentSymbol); } return result; } std::optional> LanguageServer::getDiagnostics(std::string uri) { std::vector result; auto module = m_core->m_workspace->getCurrentVersion()->getOrLoadModule( Slang::URI::fromString(Slang::UnownedStringSlice(uri.c_str())).getPath()); if (!module) return std::nullopt; for (auto& docDiag : m_core->m_workspace->getCurrentVersion()->diagnostics) { for (auto& message : docDiag.second.messages) { lsp::Diagnostics diag; diag.code = Slang::String(message.code).getBuffer(); diag.range = translate(message.range); diag.severity = (int)message.severity; diag.message = message.message.getBuffer(); result.push_back(diag); } } return result; } LanguageServer* createLanguageServer() { return new LanguageServer(); } } // namespace lsp } // namespace wgsl } // namespace slang