yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Gangzheng TongAdd CUDA the compile target for slang-playground289f3dd22

master
30.2 KiB980 linesraw
1#include "slang-wasm.h"
2
3#include "../core/slang-blob.h"
4#include "../core/slang-exception.h"
5#include "../slang/slang-language-server.h"
6
7#include <slang.h>
8#include <vector>
9
10using namespace slang;
11
12namespace slang
13{
14namespace wgsl
15{
16
17Error g_error;
18
19Error getLastError()
20{
21    Error currentError = g_error;
22    g_error = {};
23    return currentError;
24}
25
26emscripten::val getCompileTargets()
27{
28    struct TargetPair
29    {
30        const char* name;
31        SlangCompileTarget target;
32    };
33    static const TargetPair targets[] = {
34        {"GLSL", SLANG_GLSL},
35        {"HLSL", SLANG_HLSL},
36        {"WGSL", SLANG_WGSL},
37        {"SPIRV", SLANG_SPIRV},
38        {"METAL", SLANG_METAL},
39        {"CUDA", SLANG_CUDA_SOURCE},
40    };
41
42    std::vector<emscripten::val> result;
43    for (auto target : targets)
44    {
45        auto entry = emscripten::val::object();
46        entry.set("name", target.name);
47        entry.set("value", (int)target.target);
48        result.push_back(entry);
49    }
50    return emscripten::val::array(result);
51}
52
53GlobalSession* createGlobalSession()
54{
55    IGlobalSession* globalSession = nullptr;
56    {
57        SlangResult result = slang::createGlobalSession(&globalSession);
58        if (result != SLANG_OK)
59        {
60            g_error.type = std::string("USER");
61            g_error.result = result;
62            return nullptr;
63        }
64    }
65
66    return new GlobalSession(globalSession);
67}
68
69Session* GlobalSession::createSession(int compileTarget)
70{
71    Slang::ComPtr<ISession> session;
72    {
73        SessionDesc sessionDesc = {};
74        sessionDesc.structureSize = sizeof(sessionDesc);
75        constexpr SlangInt targetCount = 1;
76        TargetDesc target = {};
77        target.format = (SlangCompileTarget)compileTarget;
78        if (compileTarget == SLANG_HLSL)
79        {
80            target.profile = spFindProfile(m_interface, "sm_6_6");
81        }
82        sessionDesc.targets = &target;
83        sessionDesc.targetCount = targetCount;
84        SlangResult result = m_interface->createSession(sessionDesc, session.writeRef());
85        if (result != SLANG_OK)
86        {
87            g_error.type = std::string("USER");
88            g_error.result = result;
89            return nullptr;
90        }
91    }
92
93    return new Session(session);
94}
95
96Session::~Session()
97{
98    m_componentTypes = {};
99    auto refCount = static_cast<Slang::Linkage*>(m_interface.get())->debugGetReferenceCount();
100    m_interface = nullptr;
101}
102
103emscripten::val Session::loadModuleFromSource(
104    const std::string& slangCode,
105    const std::string& name,
106    const std::string& path)
107{
108    IModule* module = nullptr;
109    {
110        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
111        Slang::ComPtr<ISlangBlob> slangCodeBlob =
112            Slang::RawBlob::create(slangCode.c_str(), slangCode.size());
113        module = m_interface->loadModuleFromSource(
114            name.c_str(),
115            path.c_str(),
116            slangCodeBlob,
117            diagnosticsBlob.writeRef());
118        if (!module)
119        {
120            g_error.type = std::string("USER");
121            g_error.message = std::string(
122                (char*)diagnosticsBlob->getBufferPointer(),
123                (char*)diagnosticsBlob->getBufferPointer() + diagnosticsBlob->getBufferSize());
124            return emscripten::val::null();
125        }
126    }
127    return emscripten::val(Module(module, this));
128}
129
130emscripten::val Module::findEntryPointByName(const std::string& name)
131{
132    Slang::ComPtr<IEntryPoint> entryPoint;
133    {
134        SlangResult result =
135            moduleInterface()->findEntryPointByName(name.c_str(), entryPoint.writeRef());
136        if (result != SLANG_OK)
137        {
138            g_error.type = std::string("USER");
139            g_error.result = result;
140            return emscripten::val::null();
141        }
142    }
143    m_session->addComponentType(entryPoint.get());
144    return emscripten::val(EntryPoint(entryPoint.get(), m_session));
145}
146
147emscripten::val Module::findAndCheckEntryPoint(const std::string& name, int stage)
148{
149    Slang::ComPtr<IEntryPoint> entryPoint;
150    {
151        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
152        SlangResult result = moduleInterface()->findAndCheckEntryPoint(
153            name.c_str(),
154            (SlangStage)stage,
155            entryPoint.writeRef(),
156            diagnosticsBlob.writeRef());
157        if (!SLANG_SUCCEEDED(result))
158        {
159            g_error.type = std::string("USER");
160            g_error.result = result;
161
162            if (diagnosticsBlob->getBufferSize())
163            {
164                char* diagnostics = (char*)diagnosticsBlob->getBufferPointer();
165                g_error.message = std::string(diagnostics);
166            }
167            return emscripten::val::null();
168        }
169    }
170    m_session->addComponentType(entryPoint.get());
171    return emscripten::val(EntryPoint(entryPoint.get(), m_session));
172}
173
174int Module::getDefinedEntryPointCount()
175{
176    return moduleInterface()->getDefinedEntryPointCount();
177}
178
179emscripten::val Module::getDefinedEntryPoint(int index)
180{
181    if (moduleInterface()->getDefinedEntryPointCount() <= index)
182        return emscripten::val::null();
183
184    Slang::ComPtr<IEntryPoint> entryPoint;
185    {
186        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
187        SlangResult result = moduleInterface()->getDefinedEntryPoint(index, entryPoint.writeRef());
188        if (!SLANG_SUCCEEDED(result))
189        {
190            g_error.type = std::string("USER");
191            g_error.result = result;
192
193            if (diagnosticsBlob->getBufferSize())
194            {
195                char* diagnostics = (char*)diagnosticsBlob->getBufferPointer();
196                g_error.message = std::string(diagnostics);
197            }
198            return emscripten::val::null();
199        }
200    }
201    m_session->addComponentType(entryPoint.get());
202    return emscripten::val(EntryPoint(entryPoint.get(), m_session));
203}
204
205
206emscripten::val Session::createCompositeComponentType(emscripten::val components)
207{
208    if (!components.isArray())
209    {
210        g_error.type = std::string("Slang WASM Bind");
211        g_error.message = std::string("createCompositeComponentType: Components must be an array");
212        return emscripten::val::null();
213    }
214    std::vector<emscripten::val> componentsArray =
215        emscripten::vecFromJSArray<emscripten::val>(components);
216
217    Slang::ComPtr<IComponentType> composite;
218    {
219        std::vector<IComponentType*> nativeComponents;
220        for (size_t i = 0U; i < componentsArray.size(); i++)
221        {
222            auto componentVal = componentsArray[i];
223            if (componentVal.instanceof (emscripten::val::module_property("ComponentType")))
224            {
225                auto componentType = componentVal.as<ComponentType>();
226                nativeComponents.push_back(componentType.interface());
227            }
228        }
229        SlangResult result = m_interface->createCompositeComponentType(
230            nativeComponents.data(),
231            (SlangInt)nativeComponents.size(),
232            composite.writeRef());
233        if (result != SLANG_OK)
234        {
235            g_error.type = std::string("USER");
236            g_error.result = result;
237            return emscripten::val::null();
238        }
239    }
240    addComponentType(composite.get());
241    return emscripten::val(ComponentType(composite, this));
242}
243
244emscripten::val ComponentType::link()
245{
246    Slang::ComPtr<IComponentType> linkedProgram;
247    {
248        Slang::ComPtr<ISlangBlob> diagnosticBlob;
249        SlangResult result = interface()->link(linkedProgram.writeRef(), diagnosticBlob.writeRef());
250        if (result != SLANG_OK)
251        {
252            g_error.type = std::string("USER");
253            g_error.result = result;
254            g_error.message = std::string(
255                (char*)diagnosticBlob->getBufferPointer(),
256                (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize());
257            return emscripten::val::null();
258        }
259    }
260    m_session->addComponentType(linkedProgram.get());
261    return emscripten::val(ComponentType(linkedProgram, m_session));
262}
263
264std::string ComponentType::getEntryPointCode(int entryPointIndex, int targetIndex)
265{
266    {
267        Slang::ComPtr<IBlob> kernelBlob;
268        Slang::ComPtr<ISlangBlob> diagnosticBlob;
269        SlangResult result = interface()->getEntryPointCode(
270            entryPointIndex,
271            targetIndex,
272            kernelBlob.writeRef(),
273            diagnosticBlob.writeRef());
274        if (result != SLANG_OK)
275        {
276            g_error.type = std::string("USER");
277            g_error.result = result;
278            g_error.message = std::string(
279                (char*)diagnosticBlob->getBufferPointer(),
280                (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize());
281            return "";
282        }
283        std::string wgslCode = std::string(
284            (char*)kernelBlob->getBufferPointer(),
285            (char*)kernelBlob->getBufferPointer() + kernelBlob->getBufferSize());
286        return wgslCode;
287    }
288
289    return {};
290}
291
292// Since result code is binary, we can't return it as a string, we will need to use emscripten::val
293// to wrap it and return it to the javascript side.
294emscripten::val ComponentType::getEntryPointCodeBlob(int entryPointIndex, int targetIndex)
295{
296    Slang::ComPtr<IBlob> kernelBlob;
297    Slang::ComPtr<ISlangBlob> diagnosticBlob;
298    SlangResult result = interface()->getEntryPointCode(
299        entryPointIndex,
300        targetIndex,
301        kernelBlob.writeRef(),
302        diagnosticBlob.writeRef());
303    if (result != SLANG_OK)
304    {
305        g_error.type = std::string("USER");
306        g_error.result = result;
307        g_error.message = std::string(
308            (char*)diagnosticBlob->getBufferPointer(),
309            (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize());
310        return {};
311    }
312
313    const uint8_t* ptr = (uint8_t*)kernelBlob->getBufferPointer();
314    return emscripten::val(emscripten::typed_memory_view(kernelBlob->getBufferSize(), ptr));
315}
316
317std::string ComponentType::getTargetCode(int targetIndex)
318{
319    {
320        Slang::ComPtr<IBlob> kernelBlob;
321        Slang::ComPtr<ISlangBlob> diagnosticBlob;
322        SlangResult result = interface()->getTargetCode(
323            targetIndex,
324            kernelBlob.writeRef(),
325            diagnosticBlob.writeRef());
326        if (result != SLANG_OK)
327        {
328            g_error.type = std::string("USER");
329            g_error.result = result;
330            g_error.message = std::string(
331                (char*)diagnosticBlob->getBufferPointer(),
332                (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize());
333            return "";
334        }
335        std::string targetCode = std::string(
336            (char*)kernelBlob->getBufferPointer(),
337            (char*)kernelBlob->getBufferPointer() + kernelBlob->getBufferSize());
338        return targetCode;
339    }
340
341    return {};
342}
343
344// Since result code is binary, we can't return it as a string, we will need to use emscripten::val
345// to wrap it and return it to the javascript side.
346emscripten::val ComponentType::getTargetCodeBlob(int targetIndex)
347{
348    Slang::ComPtr<IBlob> kernelBlob;
349    Slang::ComPtr<ISlangBlob> diagnosticBlob;
350    SlangResult result =
351        interface()->getTargetCode(targetIndex, kernelBlob.writeRef(), diagnosticBlob.writeRef());
352    if (result != SLANG_OK)
353    {
354        g_error.type = std::string("USER");
355        g_error.result = result;
356        g_error.message = std::string(
357            (char*)diagnosticBlob->getBufferPointer(),
358            (char*)diagnosticBlob->getBufferPointer() + diagnosticBlob->getBufferSize());
359        return {};
360    }
361
362    const uint8_t* ptr = (uint8_t*)kernelBlob->getBufferPointer();
363    return emscripten::val(emscripten::typed_memory_view(kernelBlob->getBufferSize(), ptr));
364}
365
366emscripten::val ComponentType::loadStrings()
367{
368    slang::ProgramLayout* slangReflection = interface()->getLayout();
369    if (!slangReflection)
370    {
371        g_error.type = std::string("USER");
372        g_error.message = std::string("Failed to get reflection data");
373        return emscripten::val::null();
374    }
375
376    SlangUInt hashedStringCount = slangReflection->getHashedStringCount();
377    if (hashedStringCount == 0)
378    {
379        g_error.type = std::string("USER");
380        g_error.message = std::string("Warn: No reflection data found");
381        return emscripten::val::null();
382    }
383
384    size_t stringSize = 0;
385    std::vector<emscripten::val> result;
386    for (SlangUInt ii = 0; ii < hashedStringCount; ++ii)
387    {
388        // For each string we can fetch its bytes from the Slang
389        // reflection data.
390        //
391        size_t stringSize = 0;
392        char const* stringData = slangReflection->getHashedString(ii, &stringSize);
393
394        // Then we can compute the hash code for that string using
395        // another Slang API function.
396        //
397        // Note: the exact hashing algorithm that Slang uses for
398        // string literals is not currently documented, and may
399        // change in future releases of the compiler.
400        //
401        int hash = spComputeStringHash(stringData, stringSize);
402
403        emscripten::val entry = emscripten::val::object();
404        entry.set("hash", hash);
405        entry.set("string", std::string(stringData));
406        result.push_back(entry);
407    }
408    return emscripten::val::array(result);
409}
410
411ProgramLayout* ComponentType::getLayout(uint32_t targetIndex)
412{
413    return (slang::wgsl::ProgramLayout*)interface()->getLayout(targetIndex);
414}
415
416uint32_t ProgramLayout::getParameterCount()
417{
418    return interface()->getParameterCount();
419}
420
421emscripten::val ProgramLayout::toJsonObject()
422{
423    Slang::ComPtr<ISlangBlob> blob;
424    if (SLANG_FAILED(interface()->toJson(blob.writeRef())))
425        return {};
426    auto jsonString = std::string(
427        (char*)blob->getBufferPointer(),
428        (char*)blob->getBufferPointer() + blob->getBufferSize());
429    emscripten::val parsedObject =
430        emscripten::val::global("JSON").call<emscripten::val>("parse", jsonString);
431    return parsedObject;
432}
433
434VariableLayoutReflection* ProgramLayout::getParameterByIndex(uint32_t index)
435{
436    return (slang::wgsl::VariableLayoutReflection*)(interface()->getParameterByIndex(index));
437}
438
439TypeLayoutReflection* ProgramLayout::getGlobalParamsTypeLayout()
440{
441    return (slang::wgsl::TypeLayoutReflection*)(interface()->getGlobalParamsTypeLayout());
442}
443
444FunctionReflection* ProgramLayout::findFunctionByName(std::string name)
445{
446    return (slang::wgsl::FunctionReflection*)(interface()->findFunctionByName(name.c_str()));
447}
448
449EntryPointReflection* ProgramLayout::findEntryPointByName(std::string name)
450{
451    return (slang::wgsl::EntryPointReflection*)(interface()->findEntryPointByName(name.c_str()));
452}
453
454EntryPointReflection::ThreadGroupSize EntryPointReflection::getComputeThreadGroupSize()
455{
456    SlangUInt size[3];
457    interface()->getComputeThreadGroupSize(3, size);
458    return {size[0], size[1], size[2]};
459}
460
461BindingType TypeLayoutReflection::getDescriptorSetDescriptorRangeType(
462    uint32_t setIndex,
463    uint32_t rangeIndex)
464{
465    return interface()->getDescriptorSetDescriptorRangeType(setIndex, rangeIndex);
466}
467
468std::string DeclReflection::getName()
469{
470    return interface()->getName();
471}
472
473
474slang::DeclReflection::Kind DeclReflection::getKind()
475{
476    return interface()->getKind();
477}
478
479uint32_t DeclReflection::getChildrenCount()
480{
481    return interface()->getChildrenCount();
482};
483
484slang::wgsl::DeclReflection* DeclReflection::getChild(uint32_t index)
485{
486    return (slang::wgsl::DeclReflection*)interface()->getChild(index);
487}
488
489slang::wgsl::TypeReflection* DeclReflection::getType()
490{
491    return (slang::wgsl::TypeReflection*)interface()->getType();
492}
493slang::wgsl::VariableReflection* DeclReflection::asVariable()
494{
495    return (slang::wgsl::VariableReflection*)interface()->asVariable();
496}
497slang::wgsl::FunctionReflection* DeclReflection::asFunction()
498{
499    return (slang::wgsl::FunctionReflection*)interface()->asFunction();
500}
501slang::wgsl::GenericReflection* DeclReflection::asGeneric()
502{
503    return (slang::wgsl::GenericReflection*)interface()->asGeneric();
504}
505slang::wgsl::DeclReflection* DeclReflection::getParent()
506{
507    return (slang::wgsl::DeclReflection*)interface()->getParent();
508}
509
510
511std::string GenericReflection::getName()
512{
513    return interface()->getName();
514}
515
516slang::wgsl::DeclReflection* GenericReflection::asDecl()
517{
518    return (slang::wgsl::DeclReflection*)interface()->asDecl();
519}
520
521uint32_t GenericReflection::getTypeParameterCount()
522{
523    return interface()->getTypeParameterCount();
524}
525slang::wgsl::VariableReflection* GenericReflection::getTypeParameter(unsigned index)
526{
527    return (slang::wgsl::VariableReflection*)interface()->getTypeParameter(index);
528}
529uint32_t GenericReflection::getValueParameterCount()
530{
531    return interface()->getValueParameterCount();
532}
533slang::wgsl::VariableReflection* GenericReflection::getValueParameter(unsigned index)
534{
535    return (slang::wgsl::VariableReflection*)interface()->getValueParameter(index);
536}
537
538slang::wgsl::DeclReflection* GenericReflection::getInnerDecl()
539{
540    return (slang::wgsl::DeclReflection*)interface()->getInnerDecl();
541}
542
543SlangDeclKind GenericReflection::getInnerKind()
544{
545    return interface()->getInnerKind();
546}
547
548slang::wgsl::GenericReflection* GenericReflection::getOuterGenericContainer()
549{
550    return (slang::wgsl::GenericReflection*)interface()->getOuterGenericContainer();
551}
552
553std::string VariableLayoutReflection::getName()
554{
555    return interface()->getName();
556}
557
558slang::wgsl::TypeLayoutReflection* VariableLayoutReflection::getTypeLayout()
559{
560    return (slang::wgsl::TypeLayoutReflection*)(interface()->getTypeLayout());
561}
562
563uint32_t VariableLayoutReflection::getBindingIndex()
564{
565    return interface()->getBindingIndex();
566}
567
568std::string VariableReflection::getName()
569{
570    return interface()->getName();
571}
572
573uint32_t VariableReflection::getUserAttributeCount()
574{
575    return interface()->getUserAttributeCount();
576}
577
578slang::wgsl::UserAttribute* VariableReflection::getUserAttributeByIndex(uint32_t index)
579{
580    return (slang::wgsl::UserAttribute*)interface()->getUserAttributeByIndex(index);
581}
582
583bool VariableReflection::hasDefaultValue()
584{
585    return interface()->hasDefaultValue();
586}
587
588slang::wgsl::TypeReflection* VariableReflection::getType()
589{
590    return (slang::wgsl::TypeReflection*)interface()->getType();
591}
592
593Modifier* VariableReflection::findModifier(Modifier::ID id)
594{
595    return interface()->findModifier(id);
596}
597
598slang::wgsl::VariableReflection* TypeReflection::getFieldByIndex(uint32_t index)
599{
600    return (slang::wgsl::VariableReflection*)interface()->getFieldByIndex(index);
601}
602
603slang::TypeReflection::ScalarType TypeReflection::getScalarType()
604{
605    return interface()->getScalarType();
606}
607
608slang::TypeReflection::Kind TypeReflection::getKind()
609{
610    return interface()->getKind();
611}
612
613
614std::string UserAttribute::getName()
615{
616    return interface()->getName();
617}
618
619float UserAttribute::getArgumentValueFloat(uint32_t index)
620{
621    float value;
622    interface()->getArgumentValueFloat(index, &value);
623    return value;
624}
625
626std::string UserAttribute::getArgumentValueString(uint32_t index)
627{
628    size_t len = 0;
629    const char* out = interface()->getArgumentValueString(index, &len);
630    return std::string(out, len);
631}
632
633
634slang::wgsl::TypeReflection* UserAttribute::getArgumentType(uint32_t index)
635{
636    return (slang::wgsl::TypeReflection*)interface()->getArgumentType(index);
637}
638
639
640uint32_t UserAttribute::getArgumentCount()
641{
642    return interface()->getArgumentCount();
643}
644
645std::string FunctionReflection::getName()
646{
647    return interface()->getName();
648}
649
650uint32_t FunctionReflection::getUserAttributeCount()
651{
652    return interface()->getUserAttributeCount();
653}
654
655slang::wgsl::UserAttribute* FunctionReflection::getUserAttributeByIndex(uint32_t index)
656{
657    return (slang::wgsl::UserAttribute*)interface()->getUserAttributeByIndex(index);
658}
659
660namespace lsp
661{
662Position translate(Slang::LanguageServerProtocol::Position p)
663{
664    Position result;
665    result.line = p.line;
666    result.character = p.character;
667    return result;
668}
669Range translate(Slang::LanguageServerProtocol::Range r)
670{
671    Range result;
672    result.start = translate(r.start);
673    result.end = translate(r.end);
674    return result;
675}
676Location translate(Slang::LanguageServerProtocol::Location l)
677{
678    Location result;
679    result.uri = l.uri.getBuffer();
680    result.range = translate(l.range);
681    return result;
682}
683Slang::LanguageServerProtocol::Position translate(Position p)
684{
685    Slang::LanguageServerProtocol::Position result;
686    result.line = p.line;
687    result.character = p.character;
688    return result;
689}
690Slang::LanguageServerProtocol::Range translate(Range r)
691{
692    Slang::LanguageServerProtocol::Range result;
693    result.start = translate(r.start);
694    result.end = translate(r.end);
695    return result;
696}
697Slang::LanguageServerProtocol::Location translate(Location l)
698{
699    Slang::LanguageServerProtocol::Location result;
700    result.uri = l.uri.c_str();
701    result.range = translate(l.range);
702    return result;
703}
704
705LanguageServer::LanguageServer()
706{
707    Slang::LanguageServerStartupOptions options = {};
708    m_core = new Slang::LanguageServerCore(options);
709    init();
710}
711
712LanguageServer::~LanguageServer()
713{
714    delete m_core;
715}
716
717void LanguageServer::init()
718{
719    Slang::LanguageServerProtocol::InitializeParams args = {};
720    Slang::LanguageServerProtocol::WorkspaceFolder folder = {};
721    folder.uri = "file:///";
722    folder.name = "/";
723    args.workspaceFolders.add(folder);
724    m_core->init(args);
725}
726
727void LanguageServer::didOpenTextDocument(std::string uri, std::string text)
728{
729    Slang::LanguageServerProtocol::DidOpenTextDocumentParams args = {};
730    args.textDocument.uri = uri.c_str();
731    args.textDocument.languageId = "slang";
732    args.textDocument.text = text.c_str();
733    m_core->didOpenTextDocument(args);
734}
735
736void LanguageServer::didCloseTextDocument(std::string uri)
737{
738    Slang::LanguageServerProtocol::DidCloseTextDocumentParams args = {};
739    args.textDocument.uri = uri.c_str();
740    m_core->didCloseTextDocument(args);
741}
742
743void LanguageServer::didChangeTextDocument(
744    std::string uri,
745    const std::vector<lsp::TextEdit>& changes)
746{
747    Slang::LanguageServerProtocol::DidChangeTextDocumentParams args = {};
748    args.textDocument.uri = uri.c_str();
749    for (auto change : changes)
750    {
751        Slang::LanguageServerProtocol::TextDocumentContentChangeEvent lspChange;
752        lspChange.text = change.text.c_str();
753        lspChange.range = translate(change.range);
754        args.contentChanges.add(lspChange);
755    }
756    m_core->didChangeTextDocument(args);
757}
758
759std::optional<lsp::Hover> LanguageServer::hover(std::string uri, lsp::Position position)
760{
761    Slang::LanguageServerProtocol::HoverParams args = {};
762    args.textDocument.uri = uri.c_str();
763    args.position = translate(position);
764    auto coreResult = m_core->hover(args);
765    if (coreResult.isNull)
766        return std::nullopt;
767    lsp::Hover result;
768    result.contents.kind = coreResult.result.contents.kind.getBuffer();
769    result.contents.value = coreResult.result.contents.value.getBuffer();
770    result.range = translate(coreResult.result.range);
771    return result;
772}
773
774std::optional<std::vector<lsp::Location>> LanguageServer::gotoDefinition(
775    std::string uri,
776    lsp::Position position)
777{
778    Slang::LanguageServerProtocol::DefinitionParams args = {};
779    args.textDocument.uri = uri.c_str();
780    args.position = translate(position);
781    auto coreResult = m_core->gotoDefinition(args);
782    if (coreResult.isNull)
783        return std::nullopt;
784    std::vector<lsp::Location> result;
785    for (auto location : coreResult.result)
786        result.push_back(translate(location));
787    return result;
788}
789
790std::optional<std::vector<lsp::CompletionItem>> LanguageServer::completion(
791    std::string uri,
792    lsp::Position position,
793    CompletionContext context)
794{
795    Slang::LanguageServerProtocol::CompletionParams args = {};
796    args.textDocument.uri = uri.c_str();
797    args.position = translate(position);
798    args.context.triggerKind = context.triggerKind;
799    args.context.triggerCharacter = context.triggerCharacter.c_str();
800    auto coreResult = m_core->completion(args);
801    if (coreResult.isNull)
802        return std::nullopt;
803    std::vector<lsp::CompletionItem> result;
804    for (auto item : coreResult.result.items)
805    {
806        lsp::CompletionItem completionItem;
807        completionItem.label = item.label.getBuffer();
808        completionItem.kind = item.kind;
809        completionItem.detail = item.detail.getBuffer();
810        MarkupContent documentation;
811        documentation.kind = item.documentation.kind.getBuffer();
812        documentation.value = item.documentation.value.getBuffer();
813        completionItem.documentation = documentation;
814        completionItem.textEdit = std::nullopt;
815        completionItem.data = item.data.getBuffer();
816        std::vector<std::string> commitCharacters;
817        for (auto character : item.commitCharacters)
818            commitCharacters.push_back(character.getBuffer());
819        completionItem.commitCharacters = commitCharacters;
820        result.push_back(completionItem);
821    }
822    return result;
823}
824
825std::optional<lsp::CompletionItem> LanguageServer::completionResolve(lsp::CompletionItem args)
826{
827    Slang::LanguageServerProtocol::CompletionItem coreArgs = {};
828    coreArgs.label = args.label.c_str();
829    coreArgs.kind = args.kind;
830    coreArgs.detail = args.detail.c_str();
831    if (args.documentation.has_value())
832    {
833        coreArgs.documentation.kind = args.documentation.value().kind.c_str();
834        coreArgs.documentation.value = args.documentation.value().value.c_str();
835    }
836    coreArgs.data = args.data.c_str();
837    if (args.commitCharacters.has_value())
838    {
839        for (auto character : args.commitCharacters.value())
840            coreArgs.commitCharacters.add(character.c_str());
841    }
842    Slang::LanguageServerProtocol::TextEditCompletionItem editItem;
843    editItem.label = coreArgs.label;
844    editItem.kind = coreArgs.kind;
845    editItem.detail = coreArgs.detail;
846    editItem.documentation.kind = coreArgs.documentation.kind;
847    editItem.documentation.value = coreArgs.documentation.value;
848    editItem.data = coreArgs.data;
849
850    for (auto character : coreArgs.commitCharacters)
851        editItem.commitCharacters.add(character);
852
853    auto coreResult = m_core->completionResolve(coreArgs, editItem);
854    if (coreResult.isNull)
855        return std::nullopt;
856    lsp::CompletionItem result;
857    result.label = coreResult.result.label.getBuffer();
858    result.kind = coreResult.result.kind;
859    result.detail = coreResult.result.detail.getBuffer();
860    MarkupContent documentation;
861    documentation.kind = coreResult.result.documentation.kind.getBuffer();
862    documentation.value = coreResult.result.documentation.value.getBuffer();
863    result.documentation = documentation;
864    result.textEdit = std::nullopt;
865    result.data = coreResult.result.data.getBuffer();
866    std::vector<std::string> commitCharacters;
867    for (auto character : coreResult.result.commitCharacters)
868        commitCharacters.push_back(character.getBuffer());
869    result.commitCharacters = commitCharacters;
870    return result;
871}
872
873std::optional<std::vector<uint32_t>> LanguageServer::semanticTokens(std::string uri)
874{
875    Slang::LanguageServerProtocol::SemanticTokensParams args = {};
876    args.textDocument.uri = uri.c_str();
877    auto coreResult = m_core->semanticTokens(args);
878    if (coreResult.isNull)
879        return std::nullopt;
880    std::vector<uint32_t> result;
881    result.reserve((size_t)coreResult.result.data.getCount());
882    for (auto token : coreResult.result.data)
883        result.push_back(token);
884    return result;
885}
886
887std::optional<lsp::SignatureHelp> LanguageServer::signatureHelp(
888    std::string uri,
889    lsp::Position position)
890{
891    Slang::LanguageServerProtocol::SignatureHelpParams args = {};
892    args.textDocument.uri = uri.c_str();
893    args.position = translate(position);
894    auto coreResult = m_core->signatureHelp(args);
895    if (coreResult.isNull)
896        return std::nullopt;
897    lsp::SignatureHelp result;
898    for (auto signature : coreResult.result.signatures)
899    {
900        lsp::SignatureInformation signatureInfo;
901        signatureInfo.label = signature.label.getBuffer();
902        signatureInfo.documentation.kind = signature.documentation.kind.getBuffer();
903        signatureInfo.documentation.value = signature.documentation.value.getBuffer();
904        for (auto parameter : signature.parameters)
905        {
906            lsp::ParameterInformation parameterInfo;
907            parameterInfo.label[0] = parameter.label[0];
908            parameterInfo.label[1] = parameter.label[1];
909            parameterInfo.documentation.kind = parameter.documentation.kind.getBuffer();
910            parameterInfo.documentation.value = parameter.documentation.value.getBuffer();
911            signatureInfo.parameters.push_back(parameterInfo);
912        }
913        result.signatures.push_back(signatureInfo);
914    }
915    result.activeSignature = coreResult.result.activeSignature;
916    result.activeParameter = coreResult.result.activeParameter;
917    return result;
918}
919
920lsp::DocumentSymbol translate(Slang::LanguageServerProtocol::DocumentSymbol symbol)
921{
922    lsp::DocumentSymbol result;
923    result.name = symbol.name.getBuffer();
924    result.detail = symbol.detail.getBuffer();
925    result.kind = symbol.kind;
926    result.range = translate(symbol.range);
927    result.selectionRange = translate(symbol.selectionRange);
928    for (auto child : symbol.children)
929        result.children.push_back(translate(child));
930    return result;
931}
932
933std::optional<std::vector<lsp::DocumentSymbol>> LanguageServer::documentSymbol(std::string uri)
934{
935    Slang::LanguageServerProtocol::DocumentSymbolParams args = {};
936    args.textDocument.uri = uri.c_str();
937    auto coreResult = m_core->documentSymbol(args);
938    if (coreResult.isNull)
939        return std::nullopt;
940    std::vector<lsp::DocumentSymbol> result;
941    for (auto symbol : coreResult.result)
942    {
943        auto documentSymbol = translate(symbol);
944        result.push_back(documentSymbol);
945    }
946    return result;
947}
948
949std::optional<std::vector<lsp::Diagnostics>> LanguageServer::getDiagnostics(std::string uri)
950{
951    std::vector<lsp::Diagnostics> result;
952    auto module = m_core->m_workspace->getCurrentVersion()->getOrLoadModule(
953        Slang::URI::fromString(Slang::UnownedStringSlice(uri.c_str())).getPath());
954    if (!module)
955        return std::nullopt;
956    for (auto& docDiag : m_core->m_workspace->getCurrentVersion()->diagnostics)
957    {
958        for (auto& message : docDiag.second.messages)
959        {
960            lsp::Diagnostics diag;
961            diag.code = Slang::String(message.code).getBuffer();
962            diag.range = translate(message.range);
963            diag.severity = (int)message.severity;
964            diag.message = message.message.getBuffer();
965            result.push_back(diag);
966        }
967    }
968    return result;
969}
970
971
972LanguageServer* createLanguageServer()
973{
974    return new LanguageServer();
975}
976
977} // namespace lsp
978
979} // namespace wgsl
980} // namespace slang