[tint][wgsl] Stub 'ls' the language server package for WGSL.
Doesn't do anything (yet), except for handling the shutdown request.
Bug: tint:2127
Change-Id: If946e99801db40220ec36a1123702bca89341c07
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/174881
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/cmd/tintd/BUILD.bazel b/src/tint/cmd/tintd/BUILD.bazel
index 0416234..3139cdf 100644
--- a/src/tint/cmd/tintd/BUILD.bazel
+++ b/src/tint/cmd/tintd/BUILD.bazel
@@ -42,7 +42,27 @@
"main.cc",
],
deps = [
- ],
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ] + select({
+ ":tint_build_tintd": [
+
+ ],
+ "//conditions:default": [],
+ }) + select({
+ ":tint_build_tintd_and_tint_build_wgsl_reader": [
+ "//src/tint/lang/wgsl/ls",
+ ],
+ "//conditions:default": [],
+ }),
copts = COPTS,
visibility = ["//visibility:public"],
)
diff --git a/src/tint/cmd/tintd/BUILD.cmake b/src/tint/cmd/tintd/BUILD.cmake
index 3b02917..f950a1f 100644
--- a/src/tint/cmd/tintd/BUILD.cmake
+++ b/src/tint/cmd/tintd/BUILD.cmake
@@ -44,6 +44,31 @@
cmd/tintd/main.cc
)
+tint_target_add_dependencies(tint_cmd_tintd_cmd cmd
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+if(TINT_BUILD_TINTD)
+ tint_target_add_external_dependencies(tint_cmd_tintd_cmd cmd
+ "langsvr"
+ )
+endif(TINT_BUILD_TINTD)
+
+if(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_cmd_tintd_cmd cmd
+ tint_lang_wgsl_ls
+ )
+endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+
tint_target_set_output_name(tint_cmd_tintd_cmd cmd "tintd")
endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
\ No newline at end of file
diff --git a/src/tint/cmd/tintd/BUILD.gn b/src/tint/cmd/tintd/BUILD.gn
index f656d63..af1da9e 100644
--- a/src/tint/cmd/tintd/BUILD.gn
+++ b/src/tint/cmd/tintd/BUILD.gn
@@ -41,6 +41,25 @@
tint_executable("tintd") {
output_name = "tintd"
sources = [ "main.cc" ]
- deps = []
+ deps = [
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_tintd) {
+ deps += [ "${tint_src_dir}:langsvr" ]
+ }
+
+ if (tint_build_tintd && tint_build_wgsl_reader) {
+ deps += [ "${tint_src_dir}/lang/wgsl/ls" ]
+ }
}
}
diff --git a/src/tint/cmd/tintd/main.cc b/src/tint/cmd/tintd/main.cc
index b8e03bf..cf5ea15 100644
--- a/src/tint/cmd/tintd/main.cc
+++ b/src/tint/cmd/tintd/main.cc
@@ -25,7 +25,51 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#if TINT_BUILD_IS_WIN
+#include <fcntl.h> // _O_BINARY
+#include <io.h> // _setmode
+#endif // TINT_BUILD_IS_WIN
+
+#include <fstream>
+#include <iostream>
+
+#include "src/tint/lang/wgsl/ls/serve.h"
+
+namespace {
+
+class StdinStream : public langsvr::Reader {
+ public:
+ /// @copydoc langsvr::Reader
+ size_t Read(std::byte* out, size_t count) override { return fread(out, 1, count, stdin); }
+};
+
+class StdoutStream : public langsvr::Writer {
+ public:
+ /// @copydoc langsvr::Reader
+ langsvr::Result<langsvr::SuccessType> Write(const std::byte* in, size_t count) override {
+ fwrite(in, 1, count, stdout);
+ fflush(stdout);
+ return langsvr::Success;
+ }
+};
+
+} // namespace
+
int main() {
- // TODO(crbug.com/tint/2127): Stub.
+#if TINT_BUILD_IS_WIN
+ // Change stdin & stdout from text mode to binary mode.
+ // This ensures sequences of \r\n are not changed to \n.
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif // TINT_BUILD_IS_WIN
+
+ StdoutStream stdout_stream;
+ StdinStream stdin_stream;
+
+ if (auto res = tint::wgsl::ls::Serve(stdin_stream, stdout_stream); res != tint::Success) {
+ std::cerr << res.Failure();
+ return 1;
+ }
+
return 0;
}
diff --git a/src/tint/cmd/tintd/vscode/extension.js b/src/tint/cmd/tintd/vscode/extension.js
new file mode 100644
index 0000000..c98c364
--- /dev/null
+++ b/src/tint/cmd/tintd/vscode/extension.js
@@ -0,0 +1,75 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var path = require('path');
+var vscode = require('vscode');
+var langClient = require('vscode-languageclient');
+
+var LanguageClient = langClient.LanguageClient;
+
+// activate() is called when the extension is activated
+function activate(context) {
+ let serverModule = path.join(context.extensionPath, 'tintd');
+ let debugOptions = {};
+
+ // If the extension is launched in debug mode then the debug server options are used
+ // Otherwise the run options are used
+ let serverOptions = {
+ run: { command: serverModule, transport: langClient.stdio },
+ debug: { command: serverModule, transport: langClient.stdio, options: debugOptions }
+ }
+
+ // Options to control the language client
+ let clientOptions = {
+ documentSelector: ['wgsl'],
+ synchronize: {
+ // Synchronize the setting section 'wgsl' to the server
+ configurationSection: 'wgsl',
+ // Notify the server about file changes to .wgsl files contained in the workspace
+ fileEvents: vscode.workspace.createFileSystemWatcher('**/*.wgsl')
+ }
+ }
+
+ // Create the language client and start the client.
+ let disposable = new LanguageClient('wgsl', serverOptions, clientOptions).start();
+
+ // Push the disposable to the context's subscriptions so that the
+ // client can be deactivated on extension deactivation
+ context.subscriptions.push(disposable);
+
+ // Set the language configuration here instead of a language configuration
+ // file to work around https://github.com/microsoft/vscode/issues/42649.
+ vscode.languages.setLanguageConfiguration("wgsl", {
+ comments: { "lineComment": "//" },
+ });
+}
+exports.activate = activate;
+
+// this method is called when your extension is deactivated
+function deactivate() {
+}
+exports.deactivate = deactivate;
diff --git a/src/tint/cmd/tintd/vscode/package.json b/src/tint/cmd/tintd/vscode/package.json
new file mode 100644
index 0000000..4f5e66a
--- /dev/null
+++ b/src/tint/cmd/tintd/vscode/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "tintd",
+ "description": "Language support for WGSL",
+ "author": "Google",
+ "license": "BSD-3-Clause",
+ "version": "0.0.1",
+ "private": true,
+ "publisher": "Google",
+ "engines": {
+ "vscode": "^1.67.0"
+ },
+ "categories": [
+ "Programming Languages"
+ ],
+ "contributes": {
+ "languages": [
+ {
+ "id": "wgsl",
+ "extensions": [
+ "wgsl"
+ ]
+ }
+ ],
+ "grammars": [
+ {
+ "language": "wgsl",
+ "scopeName": "source.wgsl",
+ "path": "wgsl.tmLanguage.json"
+ }
+ ]
+ },
+ "dependencies": {
+ "vscode-languageclient": "^8.1.0-next.4"
+ },
+ "activationEvents": [
+ "*"
+ ],
+ "main": "./extension.js"
+}
diff --git a/src/tint/cmd/tintd/vscode/wgsl.tmLanguage.json b/src/tint/cmd/tintd/vscode/wgsl.tmLanguage.json
new file mode 100644
index 0000000..5072a29
--- /dev/null
+++ b/src/tint/cmd/tintd/vscode/wgsl.tmLanguage.json
@@ -0,0 +1,241 @@
+{
+ "name": "WGSL",
+ "scopeName": "source.wgsl",
+ "patterns": [
+ {
+ "include": "#comments"
+ },
+ {
+ "include": "#keywords"
+ },
+ {
+ "include": "#attributes"
+ },
+ {
+ "include": "#functions"
+ },
+ {
+ "include": "#function_calls"
+ },
+ {
+ "include": "#literals"
+ },
+ {
+ "include": "#punctuation"
+ }
+ ],
+ "repository": {
+ "comments": {
+ "comment": "single line comment",
+ "name": "comment.line.double-slash.wgsl",
+ "match": "\\s*//.*"
+ },
+ "functions": {
+ "patterns": [
+ {
+ "comment": "function definition",
+ "name": "meta.function.definition.wgsl",
+ "begin": "\\b(fn)\\s+([A-Za-z0-9_]+)(\\([^)]*\\))\\s+(->)\\s+([^{]+)",
+ "beginCaptures": {
+ "1": {
+ "name": "keyword.other.fn.wgsl"
+ },
+ "2": {
+ "name": "entity.name.function.wgsl"
+ },
+ "3": {
+ "name": "punctuation.brackets.round.wgsl"
+ },
+ "4": {
+ "name": "punctuation.fn.arrow.wgsl"
+ }
+ },
+ "end": "\\{",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.brackets.curly.wgsl"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#comments"
+ },
+ {
+ "include": "#keywords"
+ },
+ {
+ "include": "#function_calls"
+ },
+ {
+ "include": "#literals"
+ },
+ {
+ "include": "#punctuation"
+ }
+ ]
+ }
+ ]
+ },
+ "function_calls": {
+ "patterns": [
+ {
+ "comment": "function call",
+ "name": "meta.function.call.wgsl",
+ "begin": "([A-Za-z0-9_]+)(\\()",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.function.wgsl"
+ },
+ "2": {
+ "name": "punctuation.brackets.round.wgsl"
+ }
+ },
+ "end": "\\)",
+ "endCaptures": {
+ "0": {
+ "name": "punctuation.brackets.round.wgsl"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#comments"
+ },
+ {
+ "include": "#keywords"
+ },
+ {
+ "include": "#function_calls"
+ },
+ {
+ "include": "#literals"
+ },
+ {
+ "include": "#punctuation"
+ }
+ ]
+ }
+ ]
+ },
+ "attributes": {
+ "patterns": [
+ {
+ "comment": "attribute",
+ "name": "keyword.attribute.wgsl",
+ "match": "(@[A-Za-z0-9_]+[^(])"
+ }
+ ]
+ },
+ "literals": {
+ "patterns": [
+ {
+ "comment": "floating point literal",
+ "name": "constant.numeric.float.wgsl",
+ "match": "(-?\\b[0-9][0-9]*\\.[0-9][0-9]*)([eE][+-]?[0-9]+)?[fh]?\\b"
+ },
+ {
+ "comment": "integer literal",
+ "name": "constant.numeric.integer.wgsl",
+ "match": "-?\\b0x[0-9a-fA-F]+[iufh]?\\b|\\b0[iufh]?\\b|-?\\b[1-9][0-9]*[iufh]?\\b"
+ },
+ {
+ "comment": "boolean constant",
+ "name": "constant.language.boolean.wgsl",
+ "match": "\\b(true|false)\\b"
+ }
+ ]
+ },
+ "punctuation": {
+ "patterns": [
+ {
+ "comment": "comma",
+ "name": "punctuation.comma.wgsl",
+ "match": ","
+ },
+ {
+ "comment": "braces",
+ "name": "punctuation.brackets.curly.wgsl",
+ "match": "[{}]"
+ },
+ {
+ "comment": "parentheses",
+ "name": "punctuation.brackets.round.wgsl",
+ "match": "[()]"
+ },
+ {
+ "comment": "semicolon",
+ "name": "punctuation.semi.wgsl",
+ "match": ";"
+ },
+ {
+ "comment": "square brackets",
+ "name": "punctuation.brackets.square.wgsl",
+ "match": "[\\[\\]]"
+ },
+ {
+ "comment": "angle brackets",
+ "name": "punctuation.brackets.angle.wgsl",
+ "match": "(?<!=)[<>]"
+ },
+ {
+ "comment": "function ret",
+ "name": "punctuation.fn.ret.wgsl",
+ "match": "(->)"
+ }
+ ]
+ },
+ "keywords": {
+ "patterns": [
+ {
+ "comment": "other keywords",
+ "name": "keyword.control.wgsl",
+ "match": "\\b(alias|break|case|const_assert|continue|continuing|default|diagnostic|discard|else|enable|false|fn|for|if|loop|override|requires|return|struct|switch|true|while)\\b"
+ },
+ {
+ "comment": "reserved keywords",
+ "name": "keyword.control.wgsl.reserved",
+ "match": "\\b(NULL|Self|abstract|active|alignas|alignof|as|asm|asm_fragment|async|attribute|auto|await|become|binding_array|cast|catch|class|co_await|co_return|co_yield|coherent|column_major|common|compile|compile_fragment|concept|const_cast|consteval|constexpr|constinit|crate|debugger|decltype|delete|demote|demote_to_helper|do|dynamic_cast|enum|explicit|export|extends|extern|external|fallthrough|filter|final|finally|friend|from|fxgroup|get|goto|groupshared|highp|impl|implements|import|inline|instanceof|interface|layout|lowp|macro|macro_rules|match|mediump|meta|mod|module|move|mut|mutable|namespace|new|nil|noexcept|noinline|nointerpolation|noperspective|null|nullptr|of|operator|package|packoffset|partition|pass|patch|pixelfragment|precise|precision|premerge|priv|protected|pub|public|readonly|ref|regardless|register|reinterpret_cast|require|resource|restrict|self|set|shared|sizeof|smooth|snorm|static|static_assert|static_cast|std|subroutine|super|target|template|this|thread_local|throw|trait|try|type|typedef|typeid|typename|typeof|union|unless|unorm|unsafe|unsized|use|using|varying|virtual|volatile|wgsl|where|with|writeonly|yield)\\b"
+ },
+ {
+ "comment": "variable keywords",
+ "name": "keyword.other.wgsl storage.type.wgsl",
+ "match": "\\b(const|let|var|override)\\b"
+ },
+ {
+ "comment": "struct keyword",
+ "name": "keyword.declaration.struct.wgsl storage.type.wgsl",
+ "match": "\\b(struct)\\b"
+ },
+ {
+ "comment": "fn",
+ "name": "keyword.other.fn.wgsl",
+ "match": "\\bfn\\b"
+ },
+ {
+ "comment": "logical operators",
+ "name": "keyword.operator.logical.wgsl",
+ "match": "(\\^|\\||\\|\\||&&|<<|>>|!)(?!=)"
+ },
+ {
+ "comment": "assignment operators",
+ "name": "keyword.operator.assignment.wgsl",
+ "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|<<=|>>=)"
+ },
+ {
+ "comment": "comparison operators",
+ "name": "keyword.operator.comparison.wgsl",
+ "match": "(==|!=|<|<=|>|>=)"
+ },
+ {
+ "comment": "math operators",
+ "name": "keyword.operator.math.wgsl",
+ "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))"
+ },
+ {
+ "comment": "member access",
+ "name": "keyword.operator.access.dot.wgsl",
+ "match": "\\.(?!\\.)"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index 63b67a8..2b40c72 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -41,6 +41,7 @@
include(lang/wgsl/inspector/BUILD.cmake)
include(lang/wgsl/intrinsic/BUILD.cmake)
include(lang/wgsl/ir/BUILD.cmake)
+include(lang/wgsl/ls/BUILD.cmake)
include(lang/wgsl/program/BUILD.cmake)
include(lang/wgsl/reader/BUILD.cmake)
include(lang/wgsl/resolver/BUILD.cmake)
diff --git a/src/tint/lang/wgsl/ls/BUILD.bazel b/src/tint/lang/wgsl/ls/BUILD.bazel
new file mode 100644
index 0000000..4081683
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.bazel
@@ -0,0 +1,88 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "ls",
+ srcs = [
+ "serve.cc",
+ "server.cc",
+ ],
+ hdrs = [
+ "serve.h",
+ "server.h",
+ ],
+ deps = [
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+
+ ] + select({
+ ":tint_build_tintd": [
+
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "tint_build_tintd",
+ actual = "//src/tint:tint_build_tintd_true",
+)
+
+alias(
+ name = "tint_build_wgsl_reader",
+ actual = "//src/tint:tint_build_wgsl_reader_true",
+)
+
+selects.config_setting_group(
+ name = "tint_build_tintd_and_tint_build_wgsl_reader",
+ match_all = [
+ ":tint_build_tintd",
+ ":tint_build_wgsl_reader",
+ ],
+)
+
diff --git a/src/tint/lang/wgsl/ls/BUILD.cfg b/src/tint/lang/wgsl/ls/BUILD.cfg
new file mode 100644
index 0000000..d838768
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.cfg
@@ -0,0 +1,3 @@
+{
+ "condition": "tint_build_tintd && tint_build_wgsl_reader"
+}
diff --git a/src/tint/lang/wgsl/ls/BUILD.cmake b/src/tint/lang/wgsl/ls/BUILD.cmake
new file mode 100644
index 0000000..c0a29ea
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.cmake
@@ -0,0 +1,73 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+if(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+################################################################################
+# Target: tint_lang_wgsl_ls
+# Kind: lib
+# Condition: TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER
+################################################################################
+tint_add_target(tint_lang_wgsl_ls lib
+ lang/wgsl/ls/serve.cc
+ lang/wgsl/ls/serve.h
+ lang/wgsl/ls/server.cc
+ lang/wgsl/ls/server.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_ls lib
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_wgsl_ls lib
+ "thread"
+)
+
+if(TINT_BUILD_TINTD)
+ tint_target_add_external_dependencies(tint_lang_wgsl_ls lib
+ "langsvr"
+ )
+endif(TINT_BUILD_TINTD)
+
+endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
\ No newline at end of file
diff --git a/src/tint/lang/wgsl/ls/BUILD.gn b/src/tint/lang/wgsl/ls/BUILD.gn
new file mode 100644
index 0000000..c08f57b
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+if (tint_build_tintd && tint_build_wgsl_reader) {
+ libtint_source_set("ls") {
+ sources = [
+ "serve.cc",
+ "serve.h",
+ "server.cc",
+ "server.h",
+ ]
+ deps = [
+ "${tint_src_dir}:thread",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_tintd) {
+ deps += [ "${tint_src_dir}:langsvr" ]
+ }
+ }
+}
diff --git a/src/tint/lang/wgsl/ls/serve.cc b/src/tint/lang/wgsl/ls/serve.cc
new file mode 100644
index 0000000..241eee1
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/serve.cc
@@ -0,0 +1,123 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ls/serve.h"
+
+#include <stdio.h>
+#include <string>
+
+#include "langsvr/content_stream.h"
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/session.h"
+
+#include "src/tint/lang/wgsl/ls/server.h"
+#include "src/tint/utils/macros/compiler.h"
+#include "src/tint/utils/macros/defer.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Debug switches
+////////////////////////////////////////////////////////////////////////////////
+#define LOG_TO_FILE 0 // Log all raw protocol messages to "log.txt"
+#define WAIT_FOR_DEBUGGER 0 // Wait for a debugger to attach on startup
+
+#if WAIT_FOR_DEBUGGER
+#include <unistd.h>
+#include <thread>
+#endif
+
+#if LOG_TO_FILE
+#define LOG(msg, ...) \
+ { \
+ fprintf(log, msg "\n", ##__VA_ARGS__); \
+ fflush(log); \
+ } \
+ TINT_REQUIRE_SEMICOLON
+#else
+#define LOG(...) TINT_REQUIRE_SEMICOLON
+#endif
+
+namespace tint::wgsl::ls {
+
+namespace {
+
+#if LOG_TO_FILE
+FILE* log = nullptr;
+void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
+ if (log) {
+ LOG("\n--------------------------------------------------------------");
+ LOG("%s:%d %s", err.File(), static_cast<int>(err.Line()), err.Message().c_str());
+ LOG("--------------------------------------------------------------\n");
+ }
+}
+#endif
+
+} // namespace
+
+Result<SuccessType> Serve(langsvr::Reader& reader, langsvr::Writer& writer) {
+#if LOG_TO_FILE
+ log = fopen("log.txt", "wb");
+ TINT_DEFER(fclose(log));
+ tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
+#endif
+
+#if WAIT_FOR_DEBUGGER
+ LOG("waiting for debugger. pid: %s", std::to_string(getpid()).c_str());
+ std::this_thread::sleep_for(std::chrono::seconds(10));
+#endif
+
+ langsvr::Session session;
+ session.SetSender([&](std::string_view response) { //
+ LOG("<< %s", std::string(response).c_str());
+ return langsvr::WriteContent(writer, response);
+ });
+
+ Server server(session);
+
+ LOG("Running...");
+
+ while (!server.ShuttingDown()) {
+ auto msg = langsvr::ReadContent(reader);
+ if (msg != langsvr::Success) {
+ LOG("ERROR: %s", msg.Failure().reason.c_str());
+ break;
+ }
+ LOG(">> %s", msg.Get().c_str());
+
+ auto res = session.Receive(msg.Get());
+ if (res != langsvr::Success) {
+ LOG("ERROR: %s", res.Failure().reason.c_str());
+ break;
+ }
+
+ LOG("----------------");
+ }
+
+ LOG("Shutting down");
+ return Success;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/serve.h b/src/tint/lang/wgsl/ls/serve.h
new file mode 100644
index 0000000..774d119
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/serve.h
@@ -0,0 +1,43 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_LS_SERVE_H_
+#define SRC_TINT_LANG_WGSL_LS_SERVE_H_
+
+#include "langsvr/reader.h"
+#include "langsvr/writer.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::wgsl::ls {
+
+/// Serve creates a WGSL language server that reads from @p reader and writes to @p writer.
+/// Blocks until the server is shutdown by the client.
+Result<SuccessType> Serve(langsvr::Reader& reader, langsvr::Writer& writer);
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_SERVE_H_
diff --git a/src/tint/lang/wgsl/ls/server.cc b/src/tint/lang/wgsl/ls/server.cc
new file mode 100644
index 0000000..cc9bbe2
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/server.cc
@@ -0,0 +1,58 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ls/server.h"
+
+#include "langsvr/session.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+Server::Server(langsvr::Session& session) : session_(session) {
+ session.Register([&](const lsp::InitializeRequest&)
+ -> langsvr::Result<typename lsp::InitializeRequest::Result> {
+ lsp::InitializeResult result;
+ return result;
+ });
+
+ session.Register([&](const lsp::ShutdownRequest&) {
+ shutting_down_ = true;
+ return lsp::Null{};
+ });
+}
+
+Server::~Server() = default;
+
+Server::Logger::~Logger() {
+ lsp::WindowLogMessageNotification n;
+ n.type = lsp::MessageType::kLog;
+ n.message = msg.str();
+ (void)session.Send(n);
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/server.h b/src/tint/lang/wgsl/ls/server.h
new file mode 100644
index 0000000..333f00e
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/server.h
@@ -0,0 +1,81 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_LS_SERVER_H_
+#define SRC_TINT_LANG_WGSL_LS_SERVER_H_
+
+#include <memory>
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/session.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::wgsl::ls {
+
+/// The language server state object.
+class Server {
+ public:
+ /// Constructor
+ /// @param session the LSP session.
+ explicit Server(langsvr::Session& session);
+
+ /// Destructor
+ ~Server();
+
+ /// @returns true if the server has been requested to shut down.
+ bool ShuttingDown() const { return shutting_down_; }
+
+ private:
+ /// Logger is a string-stream like utility for logging to the client.
+ /// Append message content with '<<'. The message is sent when the logger is destructed.
+ struct Logger {
+ ~Logger();
+
+ /// @brief Appends @p value to the log message
+ /// @return this logger
+ template <typename T>
+ Logger& operator<<(T&& value) {
+ msg << value;
+ return *this;
+ }
+
+ langsvr::Session& session;
+ StringStream msg{};
+ };
+
+ /// Log constructs a new Logger to send a log message to the client.
+ Logger Log() { return Logger{session_}; }
+
+ /// The LSP session.
+ langsvr::Session& session_;
+ /// True if the server has been asked to shutdown.
+ bool shutting_down_ = false;
+};
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_SERVER_H_