Import Tint changes from Dawn
Contains a manual fix for GN builds (adding 'tint_build_tintd' definition)
Changes: - 27f0080bbe19e7be70257d6cd4dcc3867e5781b6 [tintd] Implement lsp::TextDocumentSignatureHelpRequest by Ben Clayton <bclayton@google.com>
- 2f215d1b7844f59c05a2dbb270815f5055da9c18 [tintd] Simplify installation by Ben Clayton <bclayton@google.com>
- 369d8cdfc497c0ed2f47662c273ea1cd38844893 [tintd] Implement lsp::TextDocumentInlayHintRequest by Ben Clayton <bclayton@google.com>
- 43dabe99b4d6c4bd4ccbfc1a4495a68f2135ea57 [tintd] Implement lsp::TextDocumentSemanticTokensFullRequ... by Ben Clayton <bclayton@google.com>
- ef02c4cb844521cef32af3d5a03cd7b94774d30a [tintd] Implement lsp::TextDocument[Prepare]RenameRequest by Ben Clayton <bclayton@google.com>
- aace4808de8332fbd96e23ada9feb28cff7a3108 [tintd] Stub required notifications by Ben Clayton <bclayton@google.com>
- 82ac0fd8baab81192ed83c0db3d907e72c12f528 Mark dp4a methods as `@const` in core.def. by dan sinclair <dsinclair@chromium.org>
- 06821eba8a7bdca9240c599ea9de376736cb2fa5 Re-enable disabled test. by dan sinclair <dsinclair@chromium.org>
- 1617031fad9a06afeb5ec261bac8e50d9ce78619 Change emitted name for `StageAttribute`. by dan sinclair <dsinclair@chromium.org>
- f3b93c1b2da8c55aacb49cb0763e6fcf666a8ff1 Add FoldConstants transform by dan sinclair <dsinclair@chromium.org>
- 2366f480a965d3faa74c655d32781665b719a606 [tintd] Implement lsp::TextDocumentHoverRequest by Ben Clayton <bclayton@google.com>
- 841ca1a590932d341e21ba46b7ecb21e3b60e841 Fix clang-tidy misc-include-cleaner complaints by David Neto <dneto@google.com>
- c00db02cbbfedcc03ce23a2f237468d1405a5cda [tint][ir] Skip unreachable continuing blocks by James Price <jrprice@google.com>
- 4176d450acf1e163378e2ca40325b82479c4dcdf [ir] Emit unreachable for loop body exits by James Price <jrprice@google.com>
- 02a5e844e0baf819b6c28063d5fdb77831794ef9 [spirv] Fix unreachable handling in MergeReturn by James Price <jrprice@google.com>
- c69f7695fc76ad93f44dc5c8653af1e365bf4559 [tintd] Implement TextDocumentReferencesRequest by Ben Clayton <bclayton@google.com>
- ee9f1f67b860f424787ff174363f627aa2ebf41f [tintd] Implement TextDocumentDefinitionRequest by Ben Clayton <bclayton@google.com>
- 7b1819b647abd1dd097fa62db85ed023998793ea [tintd] Implement TextDocumentDocumentSymbolRequest by Ben Clayton <bclayton@google.com>
- 3f05fea94ec7aa785921b4b095f610bcbca20588 [tintd] Implement basic document handling. by Ben Clayton <bclayton@google.com>
- b827111c8e489e61b0971232b0da133ca63a7e44 [tint] Preserve derivatives in DemoteToHelper by James Price <jrprice@google.com>
- 29b75b83730ce94abbb603f7dd4c0afbadf21192 Revert "Use abseil's build targets instead of custom ones." by Geoff Lang <geofflang@google.com>
- 8a8c582e290b89d92e129ec31b9b69794a91285d [tintd] Add package-lock.json by Ben Clayton <bclayton@google.com>
- e770313425483dc500296624f6889e9a20ee8cbf tint_cmd: Flush stderr after emitting non-error diagnostics by Antonio Maiorano <amaiorano@google.com>
- 11dc848eca01299dbc124f3e41ee8166e7e2c340 [tint][wgsl] Expand module-scope declaration sources to c... by Ben Clayton <bclayton@google.com>
- 89c05af961c8118aa2b8bacf950f9ced8223b2f7 [tint][core] Move core::intrinsic::Match() from .cc to Co... by Ben Clayton <bclayton@google.com>
- 0e3657146c65ae3275703e92a087350cc81da33c [tint][wgsl] Stub 'ls' the language server package for WG... by Ben Clayton <bclayton@google.com>
- 0a7731b7d7855b01b929f7fe364f9c208b225ab5 tint/win: fix TmpFilePath asserting in some msvc crts by Antonio Maiorano <amaiorano@google.com>
- 65afc844c0176313c8f97c87d3c20b6671aa73ba [tint][utils] Fixes for TerminalIsDark() by Ben Clayton <bclayton@google.com>
- f9a5b712d89d18e969d08e1f7b90fd0c6197b56b [tint] Add DEPS & build support for jsoncpp, langsvr by Ben Clayton <bclayton@google.com>
- ad08453d7254b0859b5524b0b5475730755ceb2a [tint][ast] Fix std140 matrix size by Ben Clayton <bclayton@google.com>
- 2ce42fc95ab7cf7bbf97a9c48876c67c95f9cb78 Use abseil's build targets instead of custom ones. by Geoff Lang <geofflang@google.com>
GitOrigin-RevId: 27f0080bbe19e7be70257d6cd4dcc3867e5781b6
Change-Id: I84800f0b65ba70f93422cce1bfea062070278f56
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/180487
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/scripts/tint_overrides_with_defaults.gni b/scripts/tint_overrides_with_defaults.gni
index 4e33a50..f6bc080 100644
--- a/scripts/tint_overrides_with_defaults.gni
+++ b/scripts/tint_overrides_with_defaults.gni
@@ -106,6 +106,11 @@
tint_build_ir_binary = tint_has_protobuf
}
+ # Build the tintd language server
+ if (!defined(tint_build_tintd)) {
+ tint_build_tintd = false
+ }
+
# Build unittests
if (!defined(tint_build_unittests)) {
tint_build_unittests = true
diff --git a/src/tint/BUILD.bazel b/src/tint/BUILD.bazel
index b3151e0..a7d7852 100644
--- a/src/tint/BUILD.bazel
+++ b/src/tint/BUILD.bazel
@@ -30,13 +30,14 @@
load(":flags.bzl", "declare_bool_flag", "declare_os_flag")
# Declares the 'tint_build_*' flags that control what parts of Tint get built
-declare_bool_flag(name = "tint_build_glsl_writer", default = False)
declare_bool_flag(name = "tint_build_glsl_validator", default = False)
+declare_bool_flag(name = "tint_build_glsl_writer", default = False)
declare_bool_flag(name = "tint_build_hlsl_writer", default = True)
declare_bool_flag(name = "tint_build_ir", default = True)
declare_bool_flag(name = "tint_build_msl_writer", default = True)
declare_bool_flag(name = "tint_build_spv_reader", default = True)
declare_bool_flag(name = "tint_build_spv_writer", default = True)
+declare_bool_flag(name = "tint_build_tintd", default = False)
declare_bool_flag(name = "tint_build_wgsl_reader", default = True)
declare_bool_flag(name = "tint_build_wgsl_writer", default = True)
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index f8fe3f2..a8ba5d2 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -284,6 +284,9 @@
"${tint_src_dir}/cmd/tint",
]
}
+ if (tint_build_tintd) {
+ deps += [ "${tint_src_dir}/cmd/tintd" ]
+ }
}
group("fuzzers") {
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index eb95b38..88fa5f8 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -66,6 +66,7 @@
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_SYNTAX_TREE_WRITER=$<BOOL:${TINT_BUILD_SYNTAX_TREE_WRITER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_READER=$<BOOL:${TINT_BUILD_WGSL_READER}>)
target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_WGSL_WRITER=$<BOOL:${TINT_BUILD_WGSL_WRITER}>)
+ target_compile_definitions(${TARGET} PUBLIC -DTINT_BUILD_TINTD=$<BOOL:${TINT_BUILD_TINTD}>)
if(TINT_BUILD_FUZZERS)
target_compile_options(${TARGET} PRIVATE "-fsanitize=fuzzer")
@@ -500,6 +501,10 @@
target_link_libraries(${TARGET} PRIVATE
absl_strings
)
+ elseif(${DEPENDENCY} STREQUAL "jsoncpp")
+ target_link_libraries(${TARGET} PRIVATE jsoncpp_static)
+ elseif(${DEPENDENCY} STREQUAL "langsvr")
+ target_link_libraries(${TARGET} PRIVATE langsvr)
elseif(${DEPENDENCY} STREQUAL "glslang")
target_link_libraries(${TARGET} PRIVATE glslang)
if(NOT MSVC)
@@ -654,12 +659,29 @@
################################################################################
+# tintd (VSCode WGSL language server)
+################################################################################
+if(TINT_BUILD_TINTD)
+ # Copy all the files out of cmd/tintd/vscode to {build}/vscode
+ set(VSCODE_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmd/tintd/vscode")
+ set(VSCODE_DST_DIR "${DAWN_BUILD_GEN_DIR}/vscode")
+
+ file(GLOB VSCODE_ASSETS RELATIVE "${VSCODE_SRC_DIR}" "${VSCODE_SRC_DIR}/*")
+ foreach(FILE ${VSCODE_ASSETS})
+ configure_file("${VSCODE_SRC_DIR}/${FILE}" "${VSCODE_DST_DIR}/${FILE}" COPYONLY)
+ endforeach()
+ set_target_properties(tint_cmd_tintd_cmd PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${VSCODE_DST_DIR}")
+endif(TINT_BUILD_TINTD)
+
+
+################################################################################
# Bespoke target settings
################################################################################
-if (MSVC)
+if(MSVC)
target_sources(tint_api PRIVATE tint.natvis)
endif()
+
################################################################################
# Additional fuzzer tests
################################################################################
diff --git a/src/tint/cmd/BUILD.cmake b/src/tint/cmd/BUILD.cmake
index cdee1d2..a7b4bcc 100644
--- a/src/tint/cmd/BUILD.cmake
+++ b/src/tint/cmd/BUILD.cmake
@@ -42,3 +42,4 @@
include(cmd/remote_compile/BUILD.cmake)
include(cmd/test/BUILD.cmake)
include(cmd/tint/BUILD.cmake)
+include(cmd/tintd/BUILD.cmake)
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index a1fbaf0..a461591 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -27,6 +27,7 @@
#include "src/tint/cmd/common/helper.h"
+#include <cstdio>
#include <iostream>
#include <utility>
#include <vector>
@@ -276,6 +277,9 @@
tint::StyledTextPrinter::Create(stderr)->Print(
formatter.Format(info.program.Diagnostics()));
}
+ // Flush any diagnostics written to stderr. We depend on these being emitted to the console
+ // before the program for end-to-end tests.
+ fflush(stderr);
}
if (!info.program.IsValid()) {
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index 0eec522..6d99985 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -164,6 +164,11 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_tintd_and_tint_build_wgsl_reader": [
+ "//src/tint/lang/wgsl/ls:test",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_wgsl_reader": [
"//src/tint/lang/wgsl/inspector:test",
"//src/tint/lang/wgsl/reader/parser:test",
@@ -218,6 +223,11 @@
)
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",
)
@@ -283,6 +293,13 @@
],
)
selects.config_setting_group(
+ name = "tint_build_tintd_and_tint_build_wgsl_reader",
+ match_all = [
+ ":tint_build_tintd",
+ ":tint_build_wgsl_reader",
+ ],
+)
+selects.config_setting_group(
name = "tint_build_wgsl_reader_and_tint_build_wgsl_writer",
match_all = [
":tint_build_wgsl_reader",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 4b50533..a280f99 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -182,6 +182,12 @@
)
endif(TINT_BUILD_SPV_WRITER AND TINT_BUILD_WGSL_READER AND TINT_BUILD_WGSL_WRITER)
+if(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
+ tint_lang_wgsl_ls_test
+ )
+endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+
if(TINT_BUILD_WGSL_READER)
tint_target_add_dependencies(tint_cmd_test_test_cmd test_cmd
tint_lang_wgsl_inspector_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 65fd5c2..59b2b6c 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -170,6 +170,10 @@
deps += [ "${tint_src_dir}/lang/spirv/writer/ast_raise:unittests" ]
}
+ if (tint_build_tintd && tint_build_wgsl_reader) {
+ deps += [ "${tint_src_dir}/lang/wgsl/ls:unittests" ]
+ }
+
if (tint_build_wgsl_reader) {
deps += [
"${tint_src_dir}/lang/wgsl/inspector:unittests",
diff --git a/src/tint/cmd/tintd/BUILD.bazel b/src/tint/cmd/tintd/BUILD.bazel
new file mode 100644
index 0000000..3139cdf
--- /dev/null
+++ b/src/tint/cmd/tintd/BUILD.bazel
@@ -0,0 +1,87 @@
+# 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_binary(
+ name = "cmd",
+ srcs = [
+ "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"],
+)
+
+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/cmd/tintd/BUILD.cfg b/src/tint/cmd/tintd/BUILD.cfg
new file mode 100644
index 0000000..b103301
--- /dev/null
+++ b/src/tint/cmd/tintd/BUILD.cfg
@@ -0,0 +1,4 @@
+{
+ "cmd": { "OutputName": "tintd" },
+ "condition": "tint_build_tintd && tint_build_wgsl_reader"
+}
diff --git a/src/tint/cmd/tintd/BUILD.cmake b/src/tint/cmd/tintd/BUILD.cmake
new file mode 100644
index 0000000..f950a1f
--- /dev/null
+++ b/src/tint/cmd/tintd/BUILD.cmake
@@ -0,0 +1,74 @@
+# 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_cmd_tintd_cmd
+# Kind: cmd
+# Condition: TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER
+################################################################################
+tint_add_target(tint_cmd_tintd_cmd cmd
+ 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
new file mode 100644
index 0000000..af1da9e
--- /dev/null
+++ b/src/tint/cmd/tintd/BUILD.gn
@@ -0,0 +1,65 @@
+# 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) {
+ tint_executable("tintd") {
+ output_name = "tintd"
+ sources = [ "main.cc" ]
+ 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
new file mode 100644
index 0000000..cf5ea15
--- /dev/null
+++ b/src/tint/cmd/tintd/main.cc
@@ -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.
+
+#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() {
+#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-lock.json b/src/tint/cmd/tintd/vscode/package-lock.json
new file mode 100644
index 0000000..ce19ef7
--- /dev/null
+++ b/src/tint/cmd/tintd/vscode/package-lock.json
@@ -0,0 +1,108 @@
+{
+ "name": "tintd",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "tintd",
+ "version": "0.0.1",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "vscode-languageclient": "^8.1.0-next.4"
+ },
+ "engines": {
+ "vscode": "^1.67.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/vscode-jsonrpc": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz",
+ "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/vscode-languageclient": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz",
+ "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==",
+ "dependencies": {
+ "minimatch": "^5.1.0",
+ "semver": "^7.3.7",
+ "vscode-languageserver-protocol": "3.17.3"
+ },
+ "engines": {
+ "vscode": "^1.67.0"
+ }
+ },
+ "node_modules/vscode-languageserver-protocol": {
+ "version": "3.17.3",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz",
+ "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==",
+ "dependencies": {
+ "vscode-jsonrpc": "8.1.0",
+ "vscode-languageserver-types": "3.17.3"
+ }
+ },
+ "node_modules/vscode-languageserver-types": {
+ "version": "3.17.3",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
+ "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ }
+ }
+}
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/externals.json b/src/tint/externals.json
index dd5d1df..dbdf96d 100644
--- a/src/tint/externals.json
+++ b/src/tint/externals.json
@@ -13,57 +13,69 @@
"benchmark/benchmark.h"
]
},
+ "jsoncpp": {
+ "IncludePatterns": [
+ "json/**"
+ ],
+ "Condition": "tint_build_tintd"
+ },
+ "langsvr": {
+ "IncludePatterns": [
+ "langsvr/**"
+ ],
+ "Condition": "tint_build_tintd"
+ },
"metal": {
"IncludePatterns": [
"Metal/Metal.h"
],
- "Condition": "tint_build_is_mac",
+ "Condition": "tint_build_is_mac"
},
"thread": {
"IncludePatterns": [
"thread"
- ],
+ ]
},
"spirv-tools": {
"IncludePatterns": [
"spirv-tools/**"
],
- "Condition": "tint_build_spv_reader || tint_build_spv_writer",
+ "Condition": "tint_build_spv_reader || tint_build_spv_writer"
},
"spirv-headers": {
"IncludePatterns": [
"spirv/**"
],
- "Condition": "tint_build_spv_reader || tint_build_spv_writer",
+ "Condition": "tint_build_spv_reader || tint_build_spv_writer"
},
"spirv-opt-internal": {
"IncludePatterns": [
"source/opt/**"
],
- "Condition": "tint_build_spv_reader || tint_build_spv_writer",
+ "Condition": "tint_build_spv_reader || tint_build_spv_writer"
},
"glslang": {
"IncludePatterns": [
"glslang/Public/ShaderLang.h"
],
- "Condition": "tint_build_glsl_validator",
+ "Condition": "tint_build_glsl_validator"
},
"glslang-res-limits": {
"IncludePatterns": [
"glslang/Public/ResourceLimits.h"
],
- "Condition": "tint_build_glsl_validator",
+ "Condition": "tint_build_glsl_validator"
},
"gtest": {
"IncludePatterns": [
"gtest/**",
- "gmock/**",
- ],
+ "gmock/**"
+ ]
},
"winsock": {
"IncludePatterns": [
"winsock2.h"
],
- "Condition": "tint_build_is_win",
- },
+ "Condition": "tint_build_is_win"
+ }
}
diff --git a/src/tint/lang/core/core.def b/src/tint/lang/core/core.def
index 7352a85..0f2d0d8 100644
--- a/src/tint/lang/core/core.def
+++ b/src/tint/lang/core/core.def
@@ -391,8 +391,8 @@
@must_use @const fn distance[T: f32_f16](T, T) -> T
@must_use @const fn distance[N: num, T: f32_f16](vec<N, T>, vec<N, T>) -> T
@must_use @const fn dot[N: num, T: fiu32_f16](vec<N, T>, vec<N, T>) -> T
-@must_use fn dot4I8Packed(u32, u32) -> i32
-@must_use fn dot4U8Packed(u32, u32) -> u32
+@must_use @const fn dot4I8Packed(u32, u32) -> i32
+@must_use @const fn dot4U8Packed(u32, u32) -> u32
@must_use @stage("fragment") fn dpdx(f32) -> f32
@must_use @stage("fragment") fn dpdx[N: num](vec<N, f32>) -> vec<N, f32>
@must_use @stage("fragment") fn dpdxCoarse(f32) -> f32
diff --git a/src/tint/lang/core/intrinsic/data.cc b/src/tint/lang/core/intrinsic/data.cc
index db57c64..8165d76 100644
--- a/src/tint/lang/core/intrinsic/data.cc
+++ b/src/tint/lang/core/intrinsic/data.cc
@@ -4261,95 +4261,97 @@
/* [19] */ &core::constant::Eval::determinant,
/* [20] */ &core::constant::Eval::distance,
/* [21] */ &core::constant::Eval::dot,
- /* [22] */ &core::constant::Eval::exp,
- /* [23] */ &core::constant::Eval::exp2,
- /* [24] */ &core::constant::Eval::extractBits,
- /* [25] */ &core::constant::Eval::faceForward,
- /* [26] */ &core::constant::Eval::firstLeadingBit,
- /* [27] */ &core::constant::Eval::firstTrailingBit,
- /* [28] */ &core::constant::Eval::floor,
- /* [29] */ &core::constant::Eval::fma,
- /* [30] */ &core::constant::Eval::fract,
- /* [31] */ &core::constant::Eval::frexp,
- /* [32] */ &core::constant::Eval::insertBits,
- /* [33] */ &core::constant::Eval::inverseSqrt,
- /* [34] */ &core::constant::Eval::ldexp,
- /* [35] */ &core::constant::Eval::length,
- /* [36] */ &core::constant::Eval::log,
- /* [37] */ &core::constant::Eval::log2,
- /* [38] */ &core::constant::Eval::max,
- /* [39] */ &core::constant::Eval::min,
- /* [40] */ &core::constant::Eval::mix,
- /* [41] */ &core::constant::Eval::modf,
- /* [42] */ &core::constant::Eval::normalize,
- /* [43] */ &core::constant::Eval::pack2x16float,
- /* [44] */ &core::constant::Eval::pack2x16snorm,
- /* [45] */ &core::constant::Eval::pack2x16unorm,
- /* [46] */ &core::constant::Eval::pack4x8snorm,
- /* [47] */ &core::constant::Eval::pack4x8unorm,
- /* [48] */ &core::constant::Eval::pack4xI8,
- /* [49] */ &core::constant::Eval::pack4xU8,
- /* [50] */ &core::constant::Eval::pack4xI8Clamp,
- /* [51] */ &core::constant::Eval::pack4xU8Clamp,
- /* [52] */ &core::constant::Eval::pow,
- /* [53] */ &core::constant::Eval::quantizeToF16,
- /* [54] */ &core::constant::Eval::radians,
- /* [55] */ &core::constant::Eval::reflect,
- /* [56] */ &core::constant::Eval::refract,
- /* [57] */ &core::constant::Eval::reverseBits,
- /* [58] */ &core::constant::Eval::round,
- /* [59] */ &core::constant::Eval::saturate,
- /* [60] */ &core::constant::Eval::select_bool,
- /* [61] */ &core::constant::Eval::select_boolvec,
- /* [62] */ &core::constant::Eval::sign,
- /* [63] */ &core::constant::Eval::sin,
- /* [64] */ &core::constant::Eval::sinh,
- /* [65] */ &core::constant::Eval::smoothstep,
- /* [66] */ &core::constant::Eval::sqrt,
- /* [67] */ &core::constant::Eval::step,
- /* [68] */ &core::constant::Eval::tan,
- /* [69] */ &core::constant::Eval::tanh,
- /* [70] */ &core::constant::Eval::transpose,
- /* [71] */ &core::constant::Eval::trunc,
- /* [72] */ &core::constant::Eval::unpack2x16float,
- /* [73] */ &core::constant::Eval::unpack2x16snorm,
- /* [74] */ &core::constant::Eval::unpack2x16unorm,
- /* [75] */ &core::constant::Eval::unpack4x8snorm,
- /* [76] */ &core::constant::Eval::unpack4x8unorm,
- /* [77] */ &core::constant::Eval::unpack4xI8,
- /* [78] */ &core::constant::Eval::unpack4xU8,
- /* [79] */ &core::constant::Eval::Not,
- /* [80] */ &core::constant::Eval::Complement,
- /* [81] */ &core::constant::Eval::UnaryMinus,
- /* [82] */ &core::constant::Eval::Plus,
- /* [83] */ &core::constant::Eval::Minus,
- /* [84] */ &core::constant::Eval::Multiply,
- /* [85] */ &core::constant::Eval::MultiplyMatVec,
- /* [86] */ &core::constant::Eval::MultiplyVecMat,
- /* [87] */ &core::constant::Eval::MultiplyMatMat,
- /* [88] */ &core::constant::Eval::Divide,
- /* [89] */ &core::constant::Eval::Modulo,
- /* [90] */ &core::constant::Eval::Xor,
- /* [91] */ &core::constant::Eval::And,
- /* [92] */ &core::constant::Eval::Or,
- /* [93] */ &core::constant::Eval::LogicalAnd,
- /* [94] */ &core::constant::Eval::LogicalOr,
- /* [95] */ &core::constant::Eval::Equal,
- /* [96] */ &core::constant::Eval::NotEqual,
- /* [97] */ &core::constant::Eval::LessThan,
- /* [98] */ &core::constant::Eval::GreaterThan,
- /* [99] */ &core::constant::Eval::LessThanEqual,
- /* [100] */ &core::constant::Eval::GreaterThanEqual,
- /* [101] */ &core::constant::Eval::ShiftLeft,
- /* [102] */ &core::constant::Eval::ShiftRight,
- /* [103] */ &core::constant::Eval::Zero,
- /* [104] */ &core::constant::Eval::Identity,
- /* [105] */ &core::constant::Eval::Conv,
- /* [106] */ &core::constant::Eval::VecSplat,
- /* [107] */ &core::constant::Eval::VecInitS,
- /* [108] */ &core::constant::Eval::VecInitM,
- /* [109] */ &core::constant::Eval::MatInitS,
- /* [110] */ &core::constant::Eval::MatInitV,
+ /* [22] */ &core::constant::Eval::dot4I8Packed,
+ /* [23] */ &core::constant::Eval::dot4U8Packed,
+ /* [24] */ &core::constant::Eval::exp,
+ /* [25] */ &core::constant::Eval::exp2,
+ /* [26] */ &core::constant::Eval::extractBits,
+ /* [27] */ &core::constant::Eval::faceForward,
+ /* [28] */ &core::constant::Eval::firstLeadingBit,
+ /* [29] */ &core::constant::Eval::firstTrailingBit,
+ /* [30] */ &core::constant::Eval::floor,
+ /* [31] */ &core::constant::Eval::fma,
+ /* [32] */ &core::constant::Eval::fract,
+ /* [33] */ &core::constant::Eval::frexp,
+ /* [34] */ &core::constant::Eval::insertBits,
+ /* [35] */ &core::constant::Eval::inverseSqrt,
+ /* [36] */ &core::constant::Eval::ldexp,
+ /* [37] */ &core::constant::Eval::length,
+ /* [38] */ &core::constant::Eval::log,
+ /* [39] */ &core::constant::Eval::log2,
+ /* [40] */ &core::constant::Eval::max,
+ /* [41] */ &core::constant::Eval::min,
+ /* [42] */ &core::constant::Eval::mix,
+ /* [43] */ &core::constant::Eval::modf,
+ /* [44] */ &core::constant::Eval::normalize,
+ /* [45] */ &core::constant::Eval::pack2x16float,
+ /* [46] */ &core::constant::Eval::pack2x16snorm,
+ /* [47] */ &core::constant::Eval::pack2x16unorm,
+ /* [48] */ &core::constant::Eval::pack4x8snorm,
+ /* [49] */ &core::constant::Eval::pack4x8unorm,
+ /* [50] */ &core::constant::Eval::pack4xI8,
+ /* [51] */ &core::constant::Eval::pack4xU8,
+ /* [52] */ &core::constant::Eval::pack4xI8Clamp,
+ /* [53] */ &core::constant::Eval::pack4xU8Clamp,
+ /* [54] */ &core::constant::Eval::pow,
+ /* [55] */ &core::constant::Eval::quantizeToF16,
+ /* [56] */ &core::constant::Eval::radians,
+ /* [57] */ &core::constant::Eval::reflect,
+ /* [58] */ &core::constant::Eval::refract,
+ /* [59] */ &core::constant::Eval::reverseBits,
+ /* [60] */ &core::constant::Eval::round,
+ /* [61] */ &core::constant::Eval::saturate,
+ /* [62] */ &core::constant::Eval::select_bool,
+ /* [63] */ &core::constant::Eval::select_boolvec,
+ /* [64] */ &core::constant::Eval::sign,
+ /* [65] */ &core::constant::Eval::sin,
+ /* [66] */ &core::constant::Eval::sinh,
+ /* [67] */ &core::constant::Eval::smoothstep,
+ /* [68] */ &core::constant::Eval::sqrt,
+ /* [69] */ &core::constant::Eval::step,
+ /* [70] */ &core::constant::Eval::tan,
+ /* [71] */ &core::constant::Eval::tanh,
+ /* [72] */ &core::constant::Eval::transpose,
+ /* [73] */ &core::constant::Eval::trunc,
+ /* [74] */ &core::constant::Eval::unpack2x16float,
+ /* [75] */ &core::constant::Eval::unpack2x16snorm,
+ /* [76] */ &core::constant::Eval::unpack2x16unorm,
+ /* [77] */ &core::constant::Eval::unpack4x8snorm,
+ /* [78] */ &core::constant::Eval::unpack4x8unorm,
+ /* [79] */ &core::constant::Eval::unpack4xI8,
+ /* [80] */ &core::constant::Eval::unpack4xU8,
+ /* [81] */ &core::constant::Eval::Not,
+ /* [82] */ &core::constant::Eval::Complement,
+ /* [83] */ &core::constant::Eval::UnaryMinus,
+ /* [84] */ &core::constant::Eval::Plus,
+ /* [85] */ &core::constant::Eval::Minus,
+ /* [86] */ &core::constant::Eval::Multiply,
+ /* [87] */ &core::constant::Eval::MultiplyMatVec,
+ /* [88] */ &core::constant::Eval::MultiplyVecMat,
+ /* [89] */ &core::constant::Eval::MultiplyMatMat,
+ /* [90] */ &core::constant::Eval::Divide,
+ /* [91] */ &core::constant::Eval::Modulo,
+ /* [92] */ &core::constant::Eval::Xor,
+ /* [93] */ &core::constant::Eval::And,
+ /* [94] */ &core::constant::Eval::Or,
+ /* [95] */ &core::constant::Eval::LogicalAnd,
+ /* [96] */ &core::constant::Eval::LogicalOr,
+ /* [97] */ &core::constant::Eval::Equal,
+ /* [98] */ &core::constant::Eval::NotEqual,
+ /* [99] */ &core::constant::Eval::LessThan,
+ /* [100] */ &core::constant::Eval::GreaterThan,
+ /* [101] */ &core::constant::Eval::LessThanEqual,
+ /* [102] */ &core::constant::Eval::GreaterThanEqual,
+ /* [103] */ &core::constant::Eval::ShiftLeft,
+ /* [104] */ &core::constant::Eval::ShiftRight,
+ /* [105] */ &core::constant::Eval::Zero,
+ /* [106] */ &core::constant::Eval::Identity,
+ /* [107] */ &core::constant::Eval::Conv,
+ /* [108] */ &core::constant::Eval::VecSplat,
+ /* [109] */ &core::constant::Eval::VecInitS,
+ /* [110] */ &core::constant::Eval::VecInitM,
+ /* [111] */ &core::constant::Eval::MatInitS,
+ /* [112] */ &core::constant::Eval::MatInitV,
};
static_assert(ConstEvalFunctionIndex::CanIndex(kConstEvalFunctions),
@@ -5058,7 +5060,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [64] */
@@ -5069,7 +5071,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(217),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [65] */
@@ -5080,7 +5082,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(106),
+ /* const_eval_fn */ ConstEvalFunctionIndex(108),
},
{
/* [66] */
@@ -5091,7 +5093,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(205),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(107),
+ /* const_eval_fn */ ConstEvalFunctionIndex(109),
},
{
/* [67] */
@@ -5102,7 +5104,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(297),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [68] */
@@ -5113,7 +5115,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(300),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [69] */
@@ -5124,7 +5126,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(303),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [70] */
@@ -5135,7 +5137,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(367),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [71] */
@@ -5146,7 +5148,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(369),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [72] */
@@ -5157,7 +5159,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(371),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [73] */
@@ -5168,7 +5170,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(390),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [74] */
@@ -5179,7 +5181,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(390),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [75] */
@@ -5190,7 +5192,7 @@
/* templates */ TemplateIndex(48),
/* parameters */ ParameterIndex(390),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [76] */
@@ -5201,7 +5203,7 @@
/* templates */ TemplateIndex(50),
/* parameters */ ParameterIndex(390),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [77] */
@@ -5212,7 +5214,7 @@
/* templates */ TemplateIndex(52),
/* parameters */ ParameterIndex(390),
/* return_matcher_indices */ MatcherIndicesIndex(186),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [78] */
@@ -5641,7 +5643,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [117] */
@@ -5652,7 +5654,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(213),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [118] */
@@ -5663,7 +5665,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(106),
+ /* const_eval_fn */ ConstEvalFunctionIndex(108),
},
{
/* [119] */
@@ -5674,7 +5676,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(205),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(107),
+ /* const_eval_fn */ ConstEvalFunctionIndex(109),
},
{
/* [120] */
@@ -5685,7 +5687,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(297),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [121] */
@@ -5696,7 +5698,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(300),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(108),
+ /* const_eval_fn */ ConstEvalFunctionIndex(110),
},
{
/* [122] */
@@ -5707,7 +5709,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(389),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [123] */
@@ -5718,7 +5720,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(389),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [124] */
@@ -5729,7 +5731,7 @@
/* templates */ TemplateIndex(48),
/* parameters */ ParameterIndex(389),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [125] */
@@ -5740,7 +5742,7 @@
/* templates */ TemplateIndex(50),
/* parameters */ ParameterIndex(389),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [126] */
@@ -5751,7 +5753,7 @@
/* templates */ TemplateIndex(52),
/* parameters */ ParameterIndex(389),
/* return_matcher_indices */ MatcherIndicesIndex(73),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [127] */
@@ -5872,7 +5874,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [138] */
@@ -5883,7 +5885,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [139] */
@@ -5894,7 +5896,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(354),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [140] */
@@ -5905,7 +5907,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(355),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [141] */
@@ -5916,7 +5918,7 @@
/* templates */ TemplateIndex(13),
/* parameters */ ParameterIndex(360),
/* return_matcher_indices */ MatcherIndicesIndex(22),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [142] */
@@ -5927,7 +5929,7 @@
/* templates */ TemplateIndex(13),
/* parameters */ ParameterIndex(359),
/* return_matcher_indices */ MatcherIndicesIndex(22),
- /* const_eval_fn */ ConstEvalFunctionIndex(84),
+ /* const_eval_fn */ ConstEvalFunctionIndex(86),
},
{
/* [143] */
@@ -5938,7 +5940,7 @@
/* templates */ TemplateIndex(22),
/* parameters */ ParameterIndex(361),
/* return_matcher_indices */ MatcherIndicesIndex(153),
- /* const_eval_fn */ ConstEvalFunctionIndex(85),
+ /* const_eval_fn */ ConstEvalFunctionIndex(87),
},
{
/* [144] */
@@ -5949,7 +5951,7 @@
/* templates */ TemplateIndex(22),
/* parameters */ ParameterIndex(363),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(86),
+ /* const_eval_fn */ ConstEvalFunctionIndex(88),
},
{
/* [145] */
@@ -5960,7 +5962,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(365),
/* return_matcher_indices */ MatcherIndicesIndex(26),
- /* const_eval_fn */ ConstEvalFunctionIndex(87),
+ /* const_eval_fn */ ConstEvalFunctionIndex(89),
},
{
/* [146] */
@@ -5971,7 +5973,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [147] */
@@ -5982,7 +5984,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(209),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [148] */
@@ -5993,7 +5995,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(106),
+ /* const_eval_fn */ ConstEvalFunctionIndex(108),
},
{
/* [149] */
@@ -6004,7 +6006,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(205),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(107),
+ /* const_eval_fn */ ConstEvalFunctionIndex(109),
},
{
/* [150] */
@@ -6015,7 +6017,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(388),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [151] */
@@ -6026,7 +6028,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(388),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [152] */
@@ -6037,7 +6039,7 @@
/* templates */ TemplateIndex(48),
/* parameters */ ParameterIndex(388),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [153] */
@@ -6048,7 +6050,7 @@
/* templates */ TemplateIndex(50),
/* parameters */ ParameterIndex(388),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [154] */
@@ -6059,7 +6061,7 @@
/* templates */ TemplateIndex(52),
/* parameters */ ParameterIndex(388),
/* return_matcher_indices */ MatcherIndicesIndex(126),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [155] */
@@ -6444,7 +6446,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [190] */
@@ -6455,7 +6457,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(391),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [191] */
@@ -6466,7 +6468,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [192] */
@@ -6477,7 +6479,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(209),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [193] */
@@ -6488,7 +6490,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(392),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [194] */
@@ -6499,7 +6501,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(393),
/* return_matcher_indices */ MatcherIndicesIndex(204),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [195] */
@@ -6510,7 +6512,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [196] */
@@ -6521,7 +6523,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(394),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [197] */
@@ -6532,7 +6534,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [198] */
@@ -6543,7 +6545,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(213),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [199] */
@@ -6554,7 +6556,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(395),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [200] */
@@ -6565,7 +6567,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(396),
/* return_matcher_indices */ MatcherIndicesIndex(210),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [201] */
@@ -6576,7 +6578,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [202] */
@@ -6587,7 +6589,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(397),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [203] */
@@ -6598,7 +6600,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [204] */
@@ -6609,7 +6611,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(217),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [205] */
@@ -6620,7 +6622,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(398),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [206] */
@@ -6631,7 +6633,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(399),
/* return_matcher_indices */ MatcherIndicesIndex(216),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [207] */
@@ -6642,7 +6644,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [208] */
@@ -6653,7 +6655,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(400),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [209] */
@@ -6664,7 +6666,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [210] */
@@ -6675,7 +6677,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(209),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [211] */
@@ -6686,7 +6688,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(401),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [212] */
@@ -6697,7 +6699,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(402),
/* return_matcher_indices */ MatcherIndicesIndex(222),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [213] */
@@ -6708,7 +6710,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [214] */
@@ -6719,7 +6721,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(403),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [215] */
@@ -6730,7 +6732,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [216] */
@@ -6741,7 +6743,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(213),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [217] */
@@ -6752,7 +6754,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(404),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [218] */
@@ -6763,7 +6765,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(405),
/* return_matcher_indices */ MatcherIndicesIndex(228),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [219] */
@@ -6774,7 +6776,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [220] */
@@ -6785,7 +6787,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(406),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [221] */
@@ -6796,7 +6798,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [222] */
@@ -6807,7 +6809,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(217),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [223] */
@@ -6818,7 +6820,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(407),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [224] */
@@ -6829,7 +6831,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(408),
/* return_matcher_indices */ MatcherIndicesIndex(234),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [225] */
@@ -6840,7 +6842,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [226] */
@@ -6851,7 +6853,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(409),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [227] */
@@ -6862,7 +6864,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [228] */
@@ -6873,7 +6875,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(209),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [229] */
@@ -6884,7 +6886,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(410),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [230] */
@@ -6895,7 +6897,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(411),
/* return_matcher_indices */ MatcherIndicesIndex(240),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [231] */
@@ -6906,7 +6908,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [232] */
@@ -6917,7 +6919,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(412),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [233] */
@@ -6928,7 +6930,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [234] */
@@ -6939,7 +6941,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(213),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [235] */
@@ -6950,7 +6952,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(413),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [236] */
@@ -6961,7 +6963,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(414),
/* return_matcher_indices */ MatcherIndicesIndex(246),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [237] */
@@ -6972,7 +6974,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [238] */
@@ -6983,7 +6985,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(415),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [239] */
@@ -6994,7 +6996,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(109),
+ /* const_eval_fn */ ConstEvalFunctionIndex(111),
},
{
/* [240] */
@@ -7005,7 +7007,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(217),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(110),
+ /* const_eval_fn */ ConstEvalFunctionIndex(112),
},
{
/* [241] */
@@ -7016,7 +7018,7 @@
/* templates */ TemplateIndex(46),
/* parameters */ ParameterIndex(416),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [242] */
@@ -7027,7 +7029,7 @@
/* templates */ TemplateIndex(44),
/* parameters */ ParameterIndex(417),
/* return_matcher_indices */ MatcherIndicesIndex(252),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [243] */
@@ -7093,7 +7095,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(82),
+ /* const_eval_fn */ ConstEvalFunctionIndex(84),
},
{
/* [249] */
@@ -7104,7 +7106,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(82),
+ /* const_eval_fn */ ConstEvalFunctionIndex(84),
},
{
/* [250] */
@@ -7115,7 +7117,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(354),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(82),
+ /* const_eval_fn */ ConstEvalFunctionIndex(84),
},
{
/* [251] */
@@ -7126,7 +7128,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(355),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(82),
+ /* const_eval_fn */ ConstEvalFunctionIndex(84),
},
{
/* [252] */
@@ -7137,7 +7139,7 @@
/* templates */ TemplateIndex(13),
/* parameters */ ParameterIndex(358),
/* return_matcher_indices */ MatcherIndicesIndex(22),
- /* const_eval_fn */ ConstEvalFunctionIndex(82),
+ /* const_eval_fn */ ConstEvalFunctionIndex(84),
},
{
/* [253] */
@@ -7148,7 +7150,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(83),
+ /* const_eval_fn */ ConstEvalFunctionIndex(85),
},
{
/* [254] */
@@ -7159,7 +7161,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(83),
+ /* const_eval_fn */ ConstEvalFunctionIndex(85),
},
{
/* [255] */
@@ -7170,7 +7172,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(354),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(83),
+ /* const_eval_fn */ ConstEvalFunctionIndex(85),
},
{
/* [256] */
@@ -7181,7 +7183,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(355),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(83),
+ /* const_eval_fn */ ConstEvalFunctionIndex(85),
},
{
/* [257] */
@@ -7192,7 +7194,7 @@
/* templates */ TemplateIndex(13),
/* parameters */ ParameterIndex(358),
/* return_matcher_indices */ MatcherIndicesIndex(22),
- /* const_eval_fn */ ConstEvalFunctionIndex(83),
+ /* const_eval_fn */ ConstEvalFunctionIndex(85),
},
{
/* [258] */
@@ -7203,7 +7205,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(88),
+ /* const_eval_fn */ ConstEvalFunctionIndex(90),
},
{
/* [259] */
@@ -7214,7 +7216,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(88),
+ /* const_eval_fn */ ConstEvalFunctionIndex(90),
},
{
/* [260] */
@@ -7225,7 +7227,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(354),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(88),
+ /* const_eval_fn */ ConstEvalFunctionIndex(90),
},
{
/* [261] */
@@ -7236,7 +7238,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(355),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(88),
+ /* const_eval_fn */ ConstEvalFunctionIndex(90),
},
{
/* [262] */
@@ -7247,7 +7249,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(89),
+ /* const_eval_fn */ ConstEvalFunctionIndex(91),
},
{
/* [263] */
@@ -7258,7 +7260,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(89),
+ /* const_eval_fn */ ConstEvalFunctionIndex(91),
},
{
/* [264] */
@@ -7269,7 +7271,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(354),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(89),
+ /* const_eval_fn */ ConstEvalFunctionIndex(91),
},
{
/* [265] */
@@ -7280,7 +7282,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(355),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(89),
+ /* const_eval_fn */ ConstEvalFunctionIndex(91),
},
{
/* [266] */
@@ -7291,7 +7293,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(91),
+ /* const_eval_fn */ ConstEvalFunctionIndex(93),
},
{
/* [267] */
@@ -7302,7 +7304,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(235),
/* return_matcher_indices */ MatcherIndicesIndex(41),
- /* const_eval_fn */ ConstEvalFunctionIndex(91),
+ /* const_eval_fn */ ConstEvalFunctionIndex(93),
},
{
/* [268] */
@@ -7313,7 +7315,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(91),
+ /* const_eval_fn */ ConstEvalFunctionIndex(93),
},
{
/* [269] */
@@ -7324,7 +7326,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(91),
+ /* const_eval_fn */ ConstEvalFunctionIndex(93),
},
{
/* [270] */
@@ -7335,7 +7337,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(92),
+ /* const_eval_fn */ ConstEvalFunctionIndex(94),
},
{
/* [271] */
@@ -7346,7 +7348,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(235),
/* return_matcher_indices */ MatcherIndicesIndex(41),
- /* const_eval_fn */ ConstEvalFunctionIndex(92),
+ /* const_eval_fn */ ConstEvalFunctionIndex(94),
},
{
/* [272] */
@@ -7357,7 +7359,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(92),
+ /* const_eval_fn */ ConstEvalFunctionIndex(94),
},
{
/* [273] */
@@ -7368,7 +7370,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(92),
+ /* const_eval_fn */ ConstEvalFunctionIndex(94),
},
{
/* [274] */
@@ -7379,7 +7381,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(40),
+ /* const_eval_fn */ ConstEvalFunctionIndex(42),
},
{
/* [275] */
@@ -7390,7 +7392,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(226),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(40),
+ /* const_eval_fn */ ConstEvalFunctionIndex(42),
},
{
/* [276] */
@@ -7401,7 +7403,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(227),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(40),
+ /* const_eval_fn */ ConstEvalFunctionIndex(42),
},
{
/* [277] */
@@ -7412,7 +7414,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(230),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(60),
+ /* const_eval_fn */ ConstEvalFunctionIndex(62),
},
{
/* [278] */
@@ -7423,7 +7425,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(222),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(60),
+ /* const_eval_fn */ ConstEvalFunctionIndex(62),
},
{
/* [279] */
@@ -7434,7 +7436,7 @@
/* templates */ TemplateIndex(33),
/* parameters */ ParameterIndex(233),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(61),
+ /* const_eval_fn */ ConstEvalFunctionIndex(63),
},
{
/* [280] */
@@ -7445,7 +7447,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(86),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [281] */
@@ -7456,7 +7458,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(386),
/* return_matcher_indices */ MatcherIndicesIndex(86),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [282] */
@@ -7467,7 +7469,7 @@
/* templates */ TemplateIndex(54),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(86),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [283] */
@@ -7478,7 +7480,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [284] */
@@ -7489,7 +7491,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [285] */
@@ -7500,7 +7502,7 @@
/* templates */ TemplateIndex(55),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [286] */
@@ -7511,7 +7513,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(49),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [287] */
@@ -7522,7 +7524,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(375),
/* return_matcher_indices */ MatcherIndicesIndex(49),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [288] */
@@ -7533,7 +7535,7 @@
/* templates */ TemplateIndex(56),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(49),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [289] */
@@ -7544,7 +7546,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(9),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [290] */
@@ -7555,7 +7557,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(387),
/* return_matcher_indices */ MatcherIndicesIndex(9),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [291] */
@@ -7566,7 +7568,7 @@
/* templates */ TemplateIndex(57),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(9),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [292] */
@@ -7577,7 +7579,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(/* invalid */),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(103),
+ /* const_eval_fn */ ConstEvalFunctionIndex(105),
},
{
/* [293] */
@@ -7588,7 +7590,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(104),
+ /* const_eval_fn */ ConstEvalFunctionIndex(106),
},
{
/* [294] */
@@ -7599,7 +7601,7 @@
/* templates */ TemplateIndex(58),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(105),
+ /* const_eval_fn */ ConstEvalFunctionIndex(107),
},
{
/* [295] */
@@ -8050,7 +8052,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(22),
+ /* const_eval_fn */ ConstEvalFunctionIndex(24),
},
{
/* [336] */
@@ -8061,7 +8063,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(22),
+ /* const_eval_fn */ ConstEvalFunctionIndex(24),
},
{
/* [337] */
@@ -8072,7 +8074,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(23),
+ /* const_eval_fn */ ConstEvalFunctionIndex(25),
},
{
/* [338] */
@@ -8083,7 +8085,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(23),
+ /* const_eval_fn */ ConstEvalFunctionIndex(25),
},
{
/* [339] */
@@ -8094,7 +8096,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(16),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(24),
+ /* const_eval_fn */ ConstEvalFunctionIndex(26),
},
{
/* [340] */
@@ -8105,7 +8107,7 @@
/* templates */ TemplateIndex(27),
/* parameters */ ParameterIndex(150),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(24),
+ /* const_eval_fn */ ConstEvalFunctionIndex(26),
},
{
/* [341] */
@@ -8116,7 +8118,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(26),
+ /* const_eval_fn */ ConstEvalFunctionIndex(28),
},
{
/* [342] */
@@ -8127,7 +8129,7 @@
/* templates */ TemplateIndex(27),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(26),
+ /* const_eval_fn */ ConstEvalFunctionIndex(28),
},
{
/* [343] */
@@ -8138,7 +8140,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(27),
+ /* const_eval_fn */ ConstEvalFunctionIndex(29),
},
{
/* [344] */
@@ -8149,7 +8151,7 @@
/* templates */ TemplateIndex(27),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(27),
+ /* const_eval_fn */ ConstEvalFunctionIndex(29),
},
{
/* [345] */
@@ -8160,7 +8162,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(28),
+ /* const_eval_fn */ ConstEvalFunctionIndex(30),
},
{
/* [346] */
@@ -8171,7 +8173,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(28),
+ /* const_eval_fn */ ConstEvalFunctionIndex(30),
},
{
/* [347] */
@@ -8182,7 +8184,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(29),
+ /* const_eval_fn */ ConstEvalFunctionIndex(31),
},
{
/* [348] */
@@ -8193,7 +8195,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(226),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(29),
+ /* const_eval_fn */ ConstEvalFunctionIndex(31),
},
{
/* [349] */
@@ -8204,7 +8206,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(30),
+ /* const_eval_fn */ ConstEvalFunctionIndex(32),
},
{
/* [350] */
@@ -8215,7 +8217,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(30),
+ /* const_eval_fn */ ConstEvalFunctionIndex(32),
},
{
/* [351] */
@@ -8226,7 +8228,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(162),
- /* const_eval_fn */ ConstEvalFunctionIndex(31),
+ /* const_eval_fn */ ConstEvalFunctionIndex(33),
},
{
/* [352] */
@@ -8237,7 +8239,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(50),
- /* const_eval_fn */ ConstEvalFunctionIndex(31),
+ /* const_eval_fn */ ConstEvalFunctionIndex(33),
},
{
/* [353] */
@@ -8248,7 +8250,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(15),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(32),
+ /* const_eval_fn */ ConstEvalFunctionIndex(34),
},
{
/* [354] */
@@ -8259,7 +8261,7 @@
/* templates */ TemplateIndex(27),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(32),
+ /* const_eval_fn */ ConstEvalFunctionIndex(34),
},
{
/* [355] */
@@ -8270,7 +8272,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(33),
+ /* const_eval_fn */ ConstEvalFunctionIndex(35),
},
{
/* [356] */
@@ -8281,7 +8283,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(33),
+ /* const_eval_fn */ ConstEvalFunctionIndex(35),
},
{
/* [357] */
@@ -8292,7 +8294,7 @@
/* templates */ TemplateIndex(9),
/* parameters */ ParameterIndex(306),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(34),
+ /* const_eval_fn */ ConstEvalFunctionIndex(36),
},
{
/* [358] */
@@ -8303,7 +8305,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(308),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(34),
+ /* const_eval_fn */ ConstEvalFunctionIndex(36),
},
{
/* [359] */
@@ -8314,7 +8316,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(35),
+ /* const_eval_fn */ ConstEvalFunctionIndex(37),
},
{
/* [360] */
@@ -8325,7 +8327,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(4),
- /* const_eval_fn */ ConstEvalFunctionIndex(35),
+ /* const_eval_fn */ ConstEvalFunctionIndex(37),
},
{
/* [361] */
@@ -8336,7 +8338,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(36),
+ /* const_eval_fn */ ConstEvalFunctionIndex(38),
},
{
/* [362] */
@@ -8347,7 +8349,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(36),
+ /* const_eval_fn */ ConstEvalFunctionIndex(38),
},
{
/* [363] */
@@ -8358,7 +8360,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(37),
+ /* const_eval_fn */ ConstEvalFunctionIndex(39),
},
{
/* [364] */
@@ -8369,7 +8371,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(37),
+ /* const_eval_fn */ ConstEvalFunctionIndex(39),
},
{
/* [365] */
@@ -8380,7 +8382,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(38),
+ /* const_eval_fn */ ConstEvalFunctionIndex(40),
},
{
/* [366] */
@@ -8391,7 +8393,7 @@
/* templates */ TemplateIndex(25),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(38),
+ /* const_eval_fn */ ConstEvalFunctionIndex(40),
},
{
/* [367] */
@@ -8402,7 +8404,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(39),
+ /* const_eval_fn */ ConstEvalFunctionIndex(41),
},
{
/* [368] */
@@ -8413,7 +8415,7 @@
/* templates */ TemplateIndex(25),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(39),
+ /* const_eval_fn */ ConstEvalFunctionIndex(41),
},
{
/* [369] */
@@ -8424,7 +8426,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(164),
- /* const_eval_fn */ ConstEvalFunctionIndex(41),
+ /* const_eval_fn */ ConstEvalFunctionIndex(43),
},
{
/* [370] */
@@ -8435,7 +8437,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(56),
- /* const_eval_fn */ ConstEvalFunctionIndex(41),
+ /* const_eval_fn */ ConstEvalFunctionIndex(43),
},
{
/* [371] */
@@ -8446,7 +8448,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(52),
+ /* const_eval_fn */ ConstEvalFunctionIndex(54),
},
{
/* [372] */
@@ -8457,7 +8459,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(52),
+ /* const_eval_fn */ ConstEvalFunctionIndex(54),
},
{
/* [373] */
@@ -8468,7 +8470,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(375),
/* return_matcher_indices */ MatcherIndicesIndex(49),
- /* const_eval_fn */ ConstEvalFunctionIndex(53),
+ /* const_eval_fn */ ConstEvalFunctionIndex(55),
},
{
/* [374] */
@@ -8479,7 +8481,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(376),
/* return_matcher_indices */ MatcherIndicesIndex(47),
- /* const_eval_fn */ ConstEvalFunctionIndex(53),
+ /* const_eval_fn */ ConstEvalFunctionIndex(55),
},
{
/* [375] */
@@ -8490,7 +8492,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(54),
+ /* const_eval_fn */ ConstEvalFunctionIndex(56),
},
{
/* [376] */
@@ -8501,7 +8503,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(54),
+ /* const_eval_fn */ ConstEvalFunctionIndex(56),
},
{
/* [377] */
@@ -8512,7 +8514,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(57),
+ /* const_eval_fn */ ConstEvalFunctionIndex(59),
},
{
/* [378] */
@@ -8523,7 +8525,7 @@
/* templates */ TemplateIndex(27),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(57),
+ /* const_eval_fn */ ConstEvalFunctionIndex(59),
},
{
/* [379] */
@@ -8534,7 +8536,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(58),
+ /* const_eval_fn */ ConstEvalFunctionIndex(60),
},
{
/* [380] */
@@ -8545,7 +8547,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(58),
+ /* const_eval_fn */ ConstEvalFunctionIndex(60),
},
{
/* [381] */
@@ -8556,7 +8558,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(59),
+ /* const_eval_fn */ ConstEvalFunctionIndex(61),
},
{
/* [382] */
@@ -8567,7 +8569,7 @@
/* templates */ TemplateIndex(13),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(59),
+ /* const_eval_fn */ ConstEvalFunctionIndex(61),
},
{
/* [383] */
@@ -8578,7 +8580,7 @@
/* templates */ TemplateIndex(36),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(62),
+ /* const_eval_fn */ ConstEvalFunctionIndex(64),
},
{
/* [384] */
@@ -8589,7 +8591,7 @@
/* templates */ TemplateIndex(35),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(62),
+ /* const_eval_fn */ ConstEvalFunctionIndex(64),
},
{
/* [385] */
@@ -8600,7 +8602,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(63),
+ /* const_eval_fn */ ConstEvalFunctionIndex(65),
},
{
/* [386] */
@@ -8611,7 +8613,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(63),
+ /* const_eval_fn */ ConstEvalFunctionIndex(65),
},
{
/* [387] */
@@ -8622,7 +8624,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(64),
+ /* const_eval_fn */ ConstEvalFunctionIndex(66),
},
{
/* [388] */
@@ -8633,7 +8635,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(64),
+ /* const_eval_fn */ ConstEvalFunctionIndex(66),
},
{
/* [389] */
@@ -8644,7 +8646,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(65),
+ /* const_eval_fn */ ConstEvalFunctionIndex(67),
},
{
/* [390] */
@@ -8655,7 +8657,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(226),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(65),
+ /* const_eval_fn */ ConstEvalFunctionIndex(67),
},
{
/* [391] */
@@ -8666,7 +8668,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(66),
+ /* const_eval_fn */ ConstEvalFunctionIndex(68),
},
{
/* [392] */
@@ -8677,7 +8679,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(66),
+ /* const_eval_fn */ ConstEvalFunctionIndex(68),
},
{
/* [393] */
@@ -8688,7 +8690,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(67),
+ /* const_eval_fn */ ConstEvalFunctionIndex(69),
},
{
/* [394] */
@@ -8699,7 +8701,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(67),
+ /* const_eval_fn */ ConstEvalFunctionIndex(69),
},
{
/* [395] */
@@ -8710,7 +8712,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(68),
+ /* const_eval_fn */ ConstEvalFunctionIndex(70),
},
{
/* [396] */
@@ -8721,7 +8723,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(68),
+ /* const_eval_fn */ ConstEvalFunctionIndex(70),
},
{
/* [397] */
@@ -8732,7 +8734,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(69),
+ /* const_eval_fn */ ConstEvalFunctionIndex(71),
},
{
/* [398] */
@@ -8743,7 +8745,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(69),
+ /* const_eval_fn */ ConstEvalFunctionIndex(71),
},
{
/* [399] */
@@ -8754,7 +8756,7 @@
/* templates */ TemplateIndex(4),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(71),
+ /* const_eval_fn */ ConstEvalFunctionIndex(73),
},
{
/* [400] */
@@ -8765,7 +8767,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(71),
+ /* const_eval_fn */ ConstEvalFunctionIndex(73),
},
{
/* [401] */
@@ -8842,7 +8844,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(79),
+ /* const_eval_fn */ ConstEvalFunctionIndex(81),
},
{
/* [408] */
@@ -8853,7 +8855,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(235),
/* return_matcher_indices */ MatcherIndicesIndex(41),
- /* const_eval_fn */ ConstEvalFunctionIndex(79),
+ /* const_eval_fn */ ConstEvalFunctionIndex(81),
},
{
/* [409] */
@@ -8864,7 +8866,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(80),
+ /* const_eval_fn */ ConstEvalFunctionIndex(82),
},
{
/* [410] */
@@ -8875,7 +8877,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(80),
+ /* const_eval_fn */ ConstEvalFunctionIndex(82),
},
{
/* [411] */
@@ -8886,7 +8888,7 @@
/* templates */ TemplateIndex(36),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(81),
+ /* const_eval_fn */ ConstEvalFunctionIndex(83),
},
{
/* [412] */
@@ -8897,7 +8899,7 @@
/* templates */ TemplateIndex(36),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(81),
+ /* const_eval_fn */ ConstEvalFunctionIndex(83),
},
{
/* [413] */
@@ -8908,7 +8910,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(90),
+ /* const_eval_fn */ ConstEvalFunctionIndex(92),
},
{
/* [414] */
@@ -8919,7 +8921,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(90),
+ /* const_eval_fn */ ConstEvalFunctionIndex(92),
},
{
/* [415] */
@@ -8930,7 +8932,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(95),
+ /* const_eval_fn */ ConstEvalFunctionIndex(97),
},
{
/* [416] */
@@ -8941,7 +8943,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(95),
+ /* const_eval_fn */ ConstEvalFunctionIndex(97),
},
{
/* [417] */
@@ -8952,7 +8954,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(96),
+ /* const_eval_fn */ ConstEvalFunctionIndex(98),
},
{
/* [418] */
@@ -8963,7 +8965,7 @@
/* templates */ TemplateIndex(32),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(96),
+ /* const_eval_fn */ ConstEvalFunctionIndex(98),
},
{
/* [419] */
@@ -8974,7 +8976,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(97),
+ /* const_eval_fn */ ConstEvalFunctionIndex(99),
},
{
/* [420] */
@@ -8985,7 +8987,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(97),
+ /* const_eval_fn */ ConstEvalFunctionIndex(99),
},
{
/* [421] */
@@ -8996,7 +8998,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(98),
+ /* const_eval_fn */ ConstEvalFunctionIndex(100),
},
{
/* [422] */
@@ -9007,7 +9009,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(98),
+ /* const_eval_fn */ ConstEvalFunctionIndex(100),
},
{
/* [423] */
@@ -9018,7 +9020,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(99),
+ /* const_eval_fn */ ConstEvalFunctionIndex(101),
},
{
/* [424] */
@@ -9029,7 +9031,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(99),
+ /* const_eval_fn */ ConstEvalFunctionIndex(101),
},
{
/* [425] */
@@ -9040,7 +9042,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(1),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(100),
+ /* const_eval_fn */ ConstEvalFunctionIndex(102),
},
{
/* [426] */
@@ -9051,7 +9053,7 @@
/* templates */ TemplateIndex(26),
/* parameters */ ParameterIndex(221),
/* return_matcher_indices */ MatcherIndicesIndex(156),
- /* const_eval_fn */ ConstEvalFunctionIndex(100),
+ /* const_eval_fn */ ConstEvalFunctionIndex(102),
},
{
/* [427] */
@@ -9062,7 +9064,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(16),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(101),
+ /* const_eval_fn */ ConstEvalFunctionIndex(103),
},
{
/* [428] */
@@ -9073,7 +9075,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(356),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(101),
+ /* const_eval_fn */ ConstEvalFunctionIndex(103),
},
{
/* [429] */
@@ -9084,7 +9086,7 @@
/* templates */ TemplateIndex(28),
/* parameters */ ParameterIndex(16),
/* return_matcher_indices */ MatcherIndicesIndex(3),
- /* const_eval_fn */ ConstEvalFunctionIndex(102),
+ /* const_eval_fn */ ConstEvalFunctionIndex(104),
},
{
/* [430] */
@@ -9095,7 +9097,7 @@
/* templates */ TemplateIndex(42),
/* parameters */ ParameterIndex(356),
/* return_matcher_indices */ MatcherIndicesIndex(44),
- /* const_eval_fn */ ConstEvalFunctionIndex(102),
+ /* const_eval_fn */ ConstEvalFunctionIndex(104),
},
{
/* [431] */
@@ -9150,7 +9152,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(86),
- /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ /* const_eval_fn */ ConstEvalFunctionIndex(22),
},
{
/* [436] */
@@ -9161,7 +9163,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ /* const_eval_fn */ ConstEvalFunctionIndex(23),
},
{
/* [437] */
@@ -9172,7 +9174,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(226),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(25),
+ /* const_eval_fn */ ConstEvalFunctionIndex(27),
},
{
/* [438] */
@@ -9183,7 +9185,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(42),
+ /* const_eval_fn */ ConstEvalFunctionIndex(44),
},
{
/* [439] */
@@ -9194,7 +9196,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(377),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(43),
+ /* const_eval_fn */ ConstEvalFunctionIndex(45),
},
{
/* [440] */
@@ -9205,7 +9207,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(377),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(44),
+ /* const_eval_fn */ ConstEvalFunctionIndex(46),
},
{
/* [441] */
@@ -9216,7 +9218,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(377),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(45),
+ /* const_eval_fn */ ConstEvalFunctionIndex(47),
},
{
/* [442] */
@@ -9227,7 +9229,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(378),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(46),
+ /* const_eval_fn */ ConstEvalFunctionIndex(48),
},
{
/* [443] */
@@ -9238,7 +9240,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(378),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(47),
+ /* const_eval_fn */ ConstEvalFunctionIndex(49),
},
{
/* [444] */
@@ -9249,7 +9251,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(379),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(48),
+ /* const_eval_fn */ ConstEvalFunctionIndex(50),
},
{
/* [445] */
@@ -9260,7 +9262,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(380),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(49),
+ /* const_eval_fn */ ConstEvalFunctionIndex(51),
},
{
/* [446] */
@@ -9271,7 +9273,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(379),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(50),
+ /* const_eval_fn */ ConstEvalFunctionIndex(52),
},
{
/* [447] */
@@ -9282,7 +9284,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(380),
/* return_matcher_indices */ MatcherIndicesIndex(78),
- /* const_eval_fn */ ConstEvalFunctionIndex(51),
+ /* const_eval_fn */ ConstEvalFunctionIndex(53),
},
{
/* [448] */
@@ -9293,7 +9295,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(149),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(55),
+ /* const_eval_fn */ ConstEvalFunctionIndex(57),
},
{
/* [449] */
@@ -9304,7 +9306,7 @@
/* templates */ TemplateIndex(8),
/* parameters */ ParameterIndex(227),
/* return_matcher_indices */ MatcherIndicesIndex(38),
- /* const_eval_fn */ ConstEvalFunctionIndex(56),
+ /* const_eval_fn */ ConstEvalFunctionIndex(58),
},
{
/* [450] */
@@ -9326,7 +9328,7 @@
/* templates */ TemplateIndex(11),
/* parameters */ ParameterIndex(381),
/* return_matcher_indices */ MatcherIndicesIndex(14),
- /* const_eval_fn */ ConstEvalFunctionIndex(70),
+ /* const_eval_fn */ ConstEvalFunctionIndex(72),
},
{
/* [452] */
@@ -9337,7 +9339,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(114),
- /* const_eval_fn */ ConstEvalFunctionIndex(72),
+ /* const_eval_fn */ ConstEvalFunctionIndex(74),
},
{
/* [453] */
@@ -9348,7 +9350,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(114),
- /* const_eval_fn */ ConstEvalFunctionIndex(73),
+ /* const_eval_fn */ ConstEvalFunctionIndex(75),
},
{
/* [454] */
@@ -9359,7 +9361,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(114),
- /* const_eval_fn */ ConstEvalFunctionIndex(74),
+ /* const_eval_fn */ ConstEvalFunctionIndex(76),
},
{
/* [455] */
@@ -9370,7 +9372,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(166),
- /* const_eval_fn */ ConstEvalFunctionIndex(75),
+ /* const_eval_fn */ ConstEvalFunctionIndex(77),
},
{
/* [456] */
@@ -9381,7 +9383,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(166),
- /* const_eval_fn */ ConstEvalFunctionIndex(76),
+ /* const_eval_fn */ ConstEvalFunctionIndex(78),
},
{
/* [457] */
@@ -9392,7 +9394,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(168),
- /* const_eval_fn */ ConstEvalFunctionIndex(77),
+ /* const_eval_fn */ ConstEvalFunctionIndex(79),
},
{
/* [458] */
@@ -9403,7 +9405,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(17),
/* return_matcher_indices */ MatcherIndicesIndex(170),
- /* const_eval_fn */ ConstEvalFunctionIndex(78),
+ /* const_eval_fn */ ConstEvalFunctionIndex(80),
},
{
/* [459] */
@@ -9469,7 +9471,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(93),
+ /* const_eval_fn */ ConstEvalFunctionIndex(95),
},
{
/* [465] */
@@ -9480,7 +9482,7 @@
/* templates */ TemplateIndex(/* invalid */),
/* parameters */ ParameterIndex(224),
/* return_matcher_indices */ MatcherIndicesIndex(43),
- /* const_eval_fn */ ConstEvalFunctionIndex(94),
+ /* const_eval_fn */ ConstEvalFunctionIndex(96),
},
};
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index 7b71604..b3ab2f6 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -153,17 +153,6 @@
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args);
-/// Match constructs a new MatchState
-/// @param context the intrinsic context
-/// @param templates the template state used for matcher evaluation
-/// @param overload the overload being evaluated
-/// @param matcher_indices pointer to a list of matcher indices
-MatchState Match(Context& context,
- TemplateState& templates,
- const OverloadInfo& overload,
- const MatcherIndex* matcher_indices,
- EvaluationStage earliest_eval_stage);
-
// Prints the list of candidates for emitting diagnostics
void PrintCandidates(StyledText& err,
Context& context,
@@ -251,11 +240,11 @@
if (auto* matcher_indices = context.data[match.overload->return_matcher_indices]) {
Any any;
return_type =
- Match(context, match.templates, *match.overload, matcher_indices, earliest_eval_stage)
+ context.Match(match.templates, *match.overload, matcher_indices, earliest_eval_stage)
.Type(&any);
if (TINT_UNLIKELY(!return_type)) {
StyledText err;
- err << "MatchState.Match() returned null";
+ err << "MatchState.MatchState() returned null";
TINT_ICE() << err.Plain();
return err;
}
@@ -322,8 +311,8 @@
auto* type = template_args[i];
if (auto* matcher_indices = context.data[tmpl.matcher_indices]) {
// Ensure type matches the template's matcher.
- type = Match(context, templates, overload, matcher_indices, earliest_eval_stage)
- .Type(type);
+ type =
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).Type(type);
if (!type) {
MATCH_FAILURE(kMismatchedExplicitTemplateTypePenalty);
continue;
@@ -344,7 +333,7 @@
for (size_t p = 0; p < num_params; p++) {
auto& parameter = context.data[overload.parameters + p];
auto* matcher_indices = context.data[parameter.matcher_indices];
- if (!Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ if (!context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(args[p])) {
MATCH_FAILURE(kMismatchedParamTypePenalty);
}
@@ -359,7 +348,7 @@
continue;
}
- auto matcher = Match(context, templates, overload, matcher_indices, earliest_eval_stage);
+ auto matcher = context.Match(templates, overload, matcher_indices, earliest_eval_stage);
switch (tmpl.kind) {
case TemplateInfo::Kind::kType: {
@@ -403,7 +392,7 @@
auto& parameter = context.data[overload.parameters + p];
auto* matcher_indices = context.data[parameter.matcher_indices];
auto* ty =
- Match(context, templates, overload, matcher_indices, earliest_eval_stage).Type(args[p]);
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).Type(args[p]);
parameters.Emplace(ty, parameter.usage);
}
@@ -476,15 +465,6 @@
return std::move(*best);
}
-MatchState Match(Context& context,
- TemplateState& templates,
- const OverloadInfo& overload,
- const MatcherIndex* matcher_indices,
- EvaluationStage earliest_eval_stage) {
- return MatchState{context.types, context.symbols, templates, context.data,
- overload, matcher_indices, earliest_eval_stage};
-}
-
void PrintCandidates(StyledText& ss,
Context& context,
VectorRef<Candidate> candidates,
@@ -548,7 +528,7 @@
if (i < template_args.Length()) {
auto* matcher_indices = context.data[tmpl.matcher_indices];
matched = !matcher_indices ||
- Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(template_args[i]);
}
@@ -573,7 +553,7 @@
bool matched = false;
if (i < args.Length()) {
- matched = Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ matched = context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(args[i]);
}
all_params_match = all_params_match && matched;
@@ -585,7 +565,7 @@
if (parameter.usage != ParameterUsage::kNone) {
ss << style::Variable(parameter.usage, ": ");
}
- Match(context, templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
ss << style::Code << " ";
if (matched) {
@@ -598,7 +578,7 @@
if (overload.return_matcher_indices.IsValid()) {
ss << " -> ";
auto* matcher_indices = context.data[overload.return_matcher_indices];
- Match(context, templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
}
bool first = true;
@@ -631,11 +611,11 @@
if (tmpl.kind == TemplateInfo::Kind::kType) {
if (auto* ty = templates.Type(i)) {
matched =
- Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(ty);
}
} else {
- matched = Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ matched = context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Num(templates.Num(i))
.IsValid();
}
@@ -647,10 +627,10 @@
ss << style::Type(tmpl.name) << style::Plain(" is ");
if (tmpl.kind == TemplateInfo::Kind::kType) {
- Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.PrintType(ss);
} else {
- Match(context, templates, overload, matcher_indices, earliest_eval_stage)
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.PrintNum(ss);
}
}
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index 9594c34..ccedb37 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -34,6 +34,7 @@
#include "src/tint/lang/core/binary_op.h"
#include "src/tint/lang/core/builtin_fn.h"
+#include "src/tint/lang/core/evaluation_stage.h"
#include "src/tint/lang/core/intrinsic/ctor_conv.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
#include "src/tint/lang/core/parameter_usage.h"
@@ -108,6 +109,18 @@
core::type::Manager& types;
/// The symbol table
SymbolTable& symbols;
+
+ /// @returns a MatchState from the context and arguments.
+ /// @param templates the template state used for matcher evaluation
+ /// @param overload the overload being evaluated
+ /// @param matcher_indices pointer to a list of matcher indices
+ MatchState Match(TemplateState& templates,
+ const OverloadInfo& overload,
+ const MatcherIndex* matcher_indices,
+ EvaluationStage earliest_eval_stage) {
+ return MatchState(types, symbols, templates, data, overload, matcher_indices,
+ earliest_eval_stage);
+ }
};
/// Candidate holds information about an overload evaluated for resolution.
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 21ff1b8..067f38c 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -66,6 +66,7 @@
#include "src/tint/lang/wgsl/ast/transform/direct_variable_access.h"
#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
#include "src/tint/lang/wgsl/ast/transform/expand_compound_assignment.h"
+#include "src/tint/lang/wgsl/ast/transform/fold_constants.h"
#include "src/tint/lang/wgsl/ast/transform/manager.h"
#include "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
#include "src/tint/lang/wgsl/ast/transform/offset_first_index.h"
@@ -145,6 +146,8 @@
ast::transform::Manager manager;
ast::transform::DataMap data;
+ manager.Add<ast::transform::FoldConstants>();
+
manager.Add<ast::transform::DisableUniformityAnalysis>();
// ExpandCompoundAssignment must come before BuiltinPolyfill
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index fc2a4b8..ffde096 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -63,6 +63,7 @@
#include "src/tint/lang/wgsl/ast/transform/direct_variable_access.h"
#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
#include "src/tint/lang/wgsl/ast/transform/expand_compound_assignment.h"
+#include "src/tint/lang/wgsl/ast/transform/fold_constants.h"
#include "src/tint/lang/wgsl/ast/transform/manager.h"
#include "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
#include "src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.h"
@@ -185,6 +186,8 @@
ast::transform::Manager manager;
ast::transform::DataMap data;
+ manager.Add<ast::transform::FoldConstants>();
+
manager.Add<ast::transform::DisableUniformityAnalysis>();
// ExpandCompoundAssignment must come before BuiltinPolyfill
diff --git a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
index 00788ed..770f7ce 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
@@ -588,11 +588,11 @@
float3 fract;
float3 whole;
};
-static const modf_result_vec3_f32 c = {(0.5f).xxx, float3(4.0f, 5.0f, 6.0f)};
[numthreads(1, 1, 1)]
void test_function() {
modf_result_vec3_f32 v = {(0.5f).xxx, float3(1.0f, 2.0f, 3.0f)};
- v = c;
+ modf_result_vec3_f32 tint_symbol = {(0.5f).xxx, float3(4.0f, 5.0f, 6.0f)};
+ v = tint_symbol;
return;
}
)");
@@ -802,11 +802,11 @@
float3 fract;
int3 exp;
};
-static const frexp_result_vec3_f32 c = {float3(0.5625f, 0.6875f, 0.8125f), (3).xxx};
[numthreads(1, 1, 1)]
void test_function() {
frexp_result_vec3_f32 v = {float3(0.75f, 0.625f, 0.875f), int3(1, 2, 2)};
- v = c;
+ frexp_result_vec3_f32 tint_symbol = {float3(0.5625f, 0.6875f, 0.8125f), (3).xxx};
+ v = tint_symbol;
return;
}
)");
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index a511c62..6b4d13d 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -72,6 +72,7 @@
#include "src/tint/lang/wgsl/ast/transform/demote_to_helper.h"
#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
#include "src/tint/lang/wgsl/ast/transform/expand_compound_assignment.h"
+#include "src/tint/lang/wgsl/ast/transform/fold_constants.h"
#include "src/tint/lang/wgsl/ast/transform/manager.h"
#include "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
#include "src/tint/lang/wgsl/ast/transform/preserve_padding.h"
@@ -147,6 +148,8 @@
ast::transform::Manager manager;
ast::transform::DataMap data;
+ manager.Add<ast::transform::FoldConstants>();
+
manager.Add<ast::transform::DisableUniformityAnalysis>();
// ExpandCompoundAssignment must come before BuiltinPolyfill
diff --git a/src/tint/lang/spirv/reader/ast_parser/import_test.cc b/src/tint/lang/spirv/reader/ast_parser/import_test.cc
index 18bb803..029db34 100644
--- a/src/tint/lang/spirv/reader/ast_parser/import_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/import_test.cc
@@ -67,15 +67,7 @@
p->DeliberatelyInvalidSpirv();
}
-TEST_F(SpvParserImportTest, DISABLED_Import_NonSemantic_IgnoredExtInsts) {
- // TODO(crbug.com/tint/1789): The NonSemantic.ClspvReflection.1 instruction
- // set grammar has changed
- // but the corresponding feature in Clspv has not yet landed.
- // See:
- // https://github.com/KhronosGroup/SPIRV-Headers/pull/308
- // https://github.com/google/clspv/pull/925
- // Disable this test until upstream has settled.
-
+TEST_F(SpvParserImportTest, Import_NonSemantic_IgnoredExtInsts) {
// This is the clspv-compiled output of this OpenCL C:
// kernel void foo(global int*A) { A=A; }
// It emits NonSemantic.ClspvReflection.1 extended instructions.
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
index 5114ce1..72a0bab 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
@@ -46,6 +46,7 @@
#include "src/tint/lang/wgsl/ast/transform/direct_variable_access.h"
#include "src/tint/lang/wgsl/ast/transform/disable_uniformity_analysis.h"
#include "src/tint/lang/wgsl/ast/transform/expand_compound_assignment.h"
+#include "src/tint/lang/wgsl/ast/transform/fold_constants.h"
#include "src/tint/lang/wgsl/ast/transform/manager.h"
#include "src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h"
#include "src/tint/lang/wgsl/ast/transform/preserve_padding.h"
@@ -65,6 +66,8 @@
ast::transform::Manager manager;
ast::transform::DataMap data;
+ manager.Add<ast::transform::FoldConstants>();
+
if (options.clamp_frag_depth) {
manager.Add<ast::transform::ClampFragDepth>();
data.Add<ast::transform::ClampFragDepth::Config>(tint::DepthRangeOffsets{0, 4});
diff --git a/src/tint/lang/spirv/writer/raise/merge_return.cc b/src/tint/lang/spirv/writer/raise/merge_return.cc
index c954430..350afa4 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return.cc
@@ -209,6 +209,12 @@
}
}
}
+
+ // If this is a non-empty block that still has no terminator, we need to insert an exit
+ // instruction (unless it is the function's top-level block).
+ if (!block->IsEmpty() && !block->Terminator() && block->Parent()) {
+ ExitFromBlock(block);
+ }
}
/// Transforms a return instruction.
@@ -262,6 +268,14 @@
block->Append(b.Store(return_val, ret->Args()[0]));
}
+ // Replace the return instruction with an exit instruction.
+ ExitFromBlock(block);
+ ret->Destroy();
+ }
+
+ /// Append an instruction to @p block that will exit from its containing control instruction.
+ /// @param block the instruction to exit from
+ void ExitFromBlock(core::ir::Block* block) {
// If the outermost control instruction is expecting exit values, then return them as
// 'undef' values.
auto* ctrl = block->Parent();
@@ -270,7 +284,6 @@
// Replace the return instruction with an exit instruction.
block->Append(b.Exit(ctrl, std::move(exit_args)));
- ret->Destroy();
}
/// Builds instructions to create a 'if(continue_execution)' conditional.
diff --git a/src/tint/lang/spirv/writer/raise/merge_return_test.cc b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
index 425f1c0..cc18a71 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return_test.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
@@ -508,6 +508,154 @@
EXPECT_EQ(expect, str());
}
+TEST_F(SpirvWriter_MergeReturnTest, IfElse_BothSidesReturn_NestedInAnotherIfWithResults) {
+ auto* cond = b.FunctionParam(ty.bool_());
+ auto* func = b.Function("foo", ty.void_());
+ func->SetParams({cond});
+
+ b.Append(func->Block(), [&] {
+ auto* outer = b.If(cond);
+ outer->SetResults(b.InstructionResult(ty.i32()), b.InstructionResult(ty.f32()));
+ b.Append(outer->True(), [&] {
+ auto* inner = b.If(cond);
+ b.Append(inner->True(), [&] { //
+ b.Return(func);
+ });
+ b.Append(inner->False(), [&] { //
+ b.Return(func);
+ });
+ b.Unreachable();
+ });
+ b.Append(outer->False(), [&] { //
+ b.Return(func);
+ });
+ b.Unreachable();
+ });
+
+ auto* src = R"(
+%foo = func(%2:bool):void -> %b1 {
+ %b1 = block {
+ %3:i32, %4:f32 = if %2 [t: %b2, f: %b3] { # if_1
+ %b2 = block { # true
+ if %2 [t: %b4, f: %b5] { # if_2
+ %b4 = block { # true
+ ret
+ }
+ %b5 = block { # false
+ ret
+ }
+ }
+ unreachable
+ }
+ %b3 = block { # false
+ ret
+ }
+ }
+ unreachable
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%2:bool):void -> %b1 {
+ %b1 = block {
+ %3:i32, %4:f32 = if %2 [t: %b2, f: %b3] { # if_1
+ %b2 = block { # true
+ if %2 [t: %b4, f: %b5] { # if_2
+ %b4 = block { # true
+ exit_if # if_2
+ }
+ %b5 = block { # false
+ exit_if # if_2
+ }
+ }
+ exit_if undef, undef # if_1
+ }
+ %b3 = block { # false
+ exit_if undef, undef # if_1
+ }
+ }
+ ret
+ }
+}
+)";
+
+ Run(MergeReturn);
+
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(SpirvWriter_MergeReturnTest, IfElse_BothSidesReturn_NestedInLoop) {
+ auto* cond = b.FunctionParam(ty.bool_());
+ auto* func = b.Function("foo", ty.void_());
+ func->SetParams({cond});
+
+ b.Append(func->Block(), [&] {
+ auto* loop = b.Loop();
+ b.Append(loop->Body(), [&] {
+ auto* inner = b.If(cond);
+ b.Append(inner->True(), [&] { //
+ b.Return(func);
+ });
+ b.Append(inner->False(), [&] { //
+ b.Return(func);
+ });
+ b.Unreachable();
+ });
+ b.Unreachable();
+ });
+
+ auto* src = R"(
+%foo = func(%2:bool):void -> %b1 {
+ %b1 = block {
+ loop [b: %b2] { # loop_1
+ %b2 = block { # body
+ if %2 [t: %b3, f: %b4] { # if_1
+ %b3 = block { # true
+ ret
+ }
+ %b4 = block { # false
+ ret
+ }
+ }
+ unreachable
+ }
+ }
+ unreachable
+ }
+}
+)";
+
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%2:bool):void -> %b1 {
+ %b1 = block {
+ loop [b: %b2] { # loop_1
+ %b2 = block { # body
+ if %2 [t: %b3, f: %b4] { # if_1
+ %b3 = block { # true
+ exit_if # if_1
+ }
+ %b4 = block { # false
+ exit_if # if_1
+ }
+ }
+ exit_loop # loop_1
+ }
+ }
+ ret
+ }
+}
+)";
+
+ Run(MergeReturn);
+
+ EXPECT_EQ(expect, str());
+}
+
TEST_F(SpirvWriter_MergeReturnTest, IfElse_ThenStatements) {
auto* global = b.Var(ty.ptr<private_, i32>());
mod.root_block->Append(global);
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/ast/stage_attribute.cc b/src/tint/lang/wgsl/ast/stage_attribute.cc
index 8369fa6..f3d8da9 100644
--- a/src/tint/lang/wgsl/ast/stage_attribute.cc
+++ b/src/tint/lang/wgsl/ast/stage_attribute.cc
@@ -42,6 +42,16 @@
StageAttribute::~StageAttribute() = default;
std::string StageAttribute::Name() const {
+ switch (stage) {
+ case PipelineStage::kVertex:
+ return "vertex";
+ case PipelineStage::kFragment:
+ return "fragment";
+ case PipelineStage::kCompute:
+ return "compute";
+ case PipelineStage::kNone:
+ break;
+ }
return "stage";
}
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.bazel b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
index 8f4e427..afec779 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
@@ -52,6 +52,7 @@
"disable_uniformity_analysis.cc",
"expand_compound_assignment.cc",
"first_index_offset.cc",
+ "fold_constants.cc",
"get_insertion_point.cc",
"hoist_to_decl_before.cc",
"manager.cc",
@@ -90,6 +91,7 @@
"disable_uniformity_analysis.h",
"expand_compound_assignment.h",
"first_index_offset.h",
+ "fold_constants.h",
"get_insertion_point.h",
"hoist_to_decl_before.h",
"manager.h",
@@ -160,6 +162,7 @@
"disable_uniformity_analysis_test.cc",
"expand_compound_assignment_test.cc",
"first_index_offset_test.cc",
+ "fold_constants_test.cc",
"get_insertion_point_test.cc",
"helper_test.h",
"hoist_to_decl_before_test.cc",
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cmake b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
index dea32eb..4f2817f 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
@@ -65,6 +65,8 @@
lang/wgsl/ast/transform/expand_compound_assignment.h
lang/wgsl/ast/transform/first_index_offset.cc
lang/wgsl/ast/transform/first_index_offset.h
+ lang/wgsl/ast/transform/fold_constants.cc
+ lang/wgsl/ast/transform/fold_constants.h
lang/wgsl/ast/transform/get_insertion_point.cc
lang/wgsl/ast/transform/get_insertion_point.h
lang/wgsl/ast/transform/hoist_to_decl_before.cc
@@ -160,6 +162,7 @@
lang/wgsl/ast/transform/disable_uniformity_analysis_test.cc
lang/wgsl/ast/transform/expand_compound_assignment_test.cc
lang/wgsl/ast/transform/first_index_offset_test.cc
+ lang/wgsl/ast/transform/fold_constants_test.cc
lang/wgsl/ast/transform/get_insertion_point_test.cc
lang/wgsl/ast/transform/helper_test.h
lang/wgsl/ast/transform/hoist_to_decl_before_test.cc
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index 70f6014..f0626b0 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -70,6 +70,8 @@
"expand_compound_assignment.h",
"first_index_offset.cc",
"first_index_offset.h",
+ "fold_constants.cc",
+ "fold_constants.h",
"get_insertion_point.cc",
"get_insertion_point.h",
"hoist_to_decl_before.cc",
@@ -161,6 +163,7 @@
"disable_uniformity_analysis_test.cc",
"expand_compound_assignment_test.cc",
"first_index_offset_test.cc",
+ "fold_constants_test.cc",
"get_insertion_point_test.cc",
"helper_test.h",
"hoist_to_decl_before_test.cc",
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
index 1b88f20..30b3982 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
@@ -153,6 +153,14 @@
<< "write to unhandled address space: " << ref->AddressSpace();
}
+ // If the RHS has side effects (which may contain derivative operations), we need to
+ // hoist it out to a separate declaration so that it does not get masked.
+ auto* rhs = sem.GetVal(assign->rhs);
+ if (rhs->HasSideEffects()) {
+ hoist_to_decl_before.Add(rhs, assign->rhs,
+ HoistToDeclBefore::VariableKind::kLet);
+ }
+
// Mask the assignment using the invocation-discarded flag.
ctx.Replace(assign, b.If(b.Not(flag), b.Block(ctx.Clone(assign))));
},
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
index 0af6dd1..ce447c0 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper_test.cc
@@ -1307,5 +1307,93 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(DemoteToHelperTest, Assignment_HoistExplicitDerivative) {
+ auto* src = R"(
+@group(0) @binding(0)
+var<storage, read_write> output : array<f32, 4>;
+
+@fragment
+fn foo(@location(0) in : f32) {
+ if (in == 0.0) {
+ discard;
+ }
+ output[u32(in)] = dpdx(in);
+}
+)";
+
+ auto* expect = R"(
+var<private> tint_discarded = false;
+
+@group(0) @binding(0) var<storage, read_write> output : array<f32, 4>;
+
+@fragment
+fn foo(@location(0) in : f32) {
+ if ((in == 0.0)) {
+ tint_discarded = true;
+ }
+ let tint_symbol : f32 = dpdx(in);
+ if (!(tint_discarded)) {
+ output[u32(in)] = tint_symbol;
+ }
+ if (tint_discarded) {
+ discard;
+ }
+}
+)";
+
+ auto got = Run<DemoteToHelper>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DemoteToHelperTest, Assignment_HoistImplicitDerivative) {
+ auto* src = R"(
+@group(0) @binding(0)
+var<storage, read_write> output : array<vec4f, 4>;
+
+@group(0) @binding(1)
+var t : texture_2d<f32>;
+
+@group(0) @binding(2)
+var s : sampler;
+
+@fragment
+fn foo(@interpolate(flat) @location(0) in : u32) {
+ if (in == 0) {
+ discard;
+ }
+ output[in] = textureSample(t, s, vec2());
+}
+)";
+
+ auto* expect = R"(
+var<private> tint_discarded = false;
+
+@group(0) @binding(0) var<storage, read_write> output : array<vec4f, 4>;
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn foo(@interpolate(flat) @location(0) in : u32) {
+ if ((in == 0)) {
+ tint_discarded = true;
+ }
+ let tint_symbol : vec4<f32> = textureSample(t, s, vec2());
+ if (!(tint_discarded)) {
+ output[in] = tint_symbol;
+ }
+ if (tint_discarded) {
+ discard;
+ }
+}
+)";
+
+ auto got = Run<DemoteToHelper>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
} // namespace
} // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/ast/transform/fold_constants.cc b/src/tint/lang/wgsl/ast/transform/fold_constants.cc
new file mode 100644
index 0000000..6eeb7d8
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/transform/fold_constants.cc
@@ -0,0 +1,134 @@
+// 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/ast/transform/fold_constants.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/constant/splat.h"
+#include "src/tint/lang/core/fluent_types.h"
+#include "src/tint/lang/core/type/abstract_float.h"
+#include "src/tint/lang/core/type/abstract_int.h"
+#include "src/tint/lang/core/type/bool.h"
+#include "src/tint/lang/wgsl/program/clone_context.h"
+#include "src/tint/lang/wgsl/program/program_builder.h"
+#include "src/tint/lang/wgsl/resolver/resolve.h"
+#include "src/tint/utils/rtti/switch.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::FoldConstants);
+
+namespace tint::ast::transform {
+namespace {
+
+struct State {
+ enum class Splat {
+ kAllowed,
+ kDisallowed,
+ };
+
+ const ast::Expression* Constant(const core::constant::Value* c) {
+ auto composite = [&](Splat splat) -> const ast::Expression* {
+ auto ty = FoldConstants::CreateASTTypeFor(ctx, c->Type());
+ if (c->AllZero()) {
+ return b.Call(ty);
+ }
+ if (splat == Splat::kAllowed && c->Is<core::constant::Splat>()) {
+ return b.Call(ty, Constant(c->Index(0)));
+ }
+
+ Vector<const ast::Expression*, 8> els;
+ for (size_t i = 0, n = c->NumElements(); i < n; i++) {
+ els.Push(Constant(c->Index(i)));
+ }
+ return b.Call(ty, std::move(els));
+ };
+
+ return tint::Switch(
+ c->Type(), //
+ [&](const core::type::AbstractFloat*) { return b.Expr(c->ValueAs<AFloat>()); },
+ [&](const core::type::AbstractInt*) { return b.Expr(c->ValueAs<AInt>()); },
+ [&](const core::type::I32*) { return b.Expr(c->ValueAs<i32>()); },
+ [&](const core::type::U32*) { return b.Expr(c->ValueAs<u32>()); },
+ [&](const core::type::F32*) { return b.Expr(c->ValueAs<f32>()); },
+ [&](const core::type::F16*) { return b.Expr(c->ValueAs<f16>()); },
+ [&](const core::type::Bool*) { return b.Expr(c->ValueAs<bool>()); },
+ [&](const core::type::Array*) { return composite(Splat::kDisallowed); },
+ [&](const core::type::Vector*) { return composite(Splat::kAllowed); },
+ [&](const core::type::Matrix*) { return composite(Splat::kDisallowed); },
+ [&](const core::type::Struct*) { return composite(Splat::kDisallowed); },
+ TINT_ICE_ON_NO_MATCH);
+ }
+
+ Transform::ApplyResult Run() {
+ ctx.ReplaceAll([&](const Expression* expr) -> const Expression* {
+ auto& sem = ctx.src->Sem();
+ auto* ve = sem.Get<sem::ValueExpression>(expr);
+
+ // No value expression SEM node found
+ if (!ve) {
+ return nullptr;
+ }
+
+ auto* cv = ve->ConstantValue();
+
+ // No constant value for this expression
+ if (!cv) {
+ return nullptr;
+ }
+
+ if (cv->Type()->HoldsAbstract() && !cv->Type()->is_float_scalar() &&
+ !cv->Type()->is_signed_integer_scalar() &&
+ !cv->Type()->is_unsigned_integer_scalar()) {
+ return nullptr;
+ }
+
+ return Constant(cv);
+ });
+
+ ctx.Clone();
+ return resolver::Resolve(b);
+ }
+
+ const Program& src;
+ ProgramBuilder b;
+ program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
+};
+
+} // namespace
+
+FoldConstants::FoldConstants() = default;
+
+FoldConstants::~FoldConstants() = default;
+
+Transform::ApplyResult FoldConstants::Apply(const Program& src, const DataMap&, DataMap&) const {
+ State s{src, {}};
+ return s.Run();
+}
+
+} // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/ast/transform/fold_constants.h b/src/tint/lang/wgsl/ast/transform/fold_constants.h
new file mode 100644
index 0000000..c9057cd
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/transform/fold_constants.h
@@ -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.
+
+#ifndef SRC_TINT_LANG_WGSL_AST_TRANSFORM_FOLD_CONSTANTS_H_
+#define SRC_TINT_LANG_WGSL_AST_TRANSFORM_FOLD_CONSTANTS_H_
+
+#include "src/tint/lang/wgsl/ast/transform/transform.h"
+
+namespace tint::ast::transform {
+
+/// A transform that replaces constant expressions with the constant values.
+///
+/// # Example
+/// ```
+/// const a = false && true;
+/// const b = sin(1);
+/// ```
+///
+/// ```
+/// const a = false;
+/// const b = 0.841470;
+/// ```
+class FoldConstants final : public Castable<FoldConstants, Transform> {
+ public:
+ /// Constructor
+ FoldConstants();
+
+ /// Destructor
+ ~FoldConstants() override;
+
+ /// @copydoc Transform::Apply
+ ApplyResult Apply(const Program& program,
+ const DataMap& inputs,
+ DataMap& outpus) const override;
+
+ private:
+ const ast::Expression* Constant(const core::constant::Value* c);
+};
+
+} // namespace tint::ast::transform
+
+#endif // SRC_TINT_LANG_WGSL_AST_TRANSFORM_FOLD_CONSTANTS_H_
diff --git a/src/tint/lang/wgsl/ast/transform/fold_constants_test.cc b/src/tint/lang/wgsl/ast/transform/fold_constants_test.cc
new file mode 100644
index 0000000..081f90f
--- /dev/null
+++ b/src/tint/lang/wgsl/ast/transform/fold_constants_test.cc
@@ -0,0 +1,440 @@
+// 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/ast/transform/fold_constants.h"
+
+#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
+
+namespace tint::ast::transform {
+namespace {
+
+using FoldConstantsTest = TransformTest;
+
+TEST_F(FoldConstantsTest, NoFolding) {
+ auto* src = R"(
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto* expect = R"(
+@vertex
+fn main() -> @builtin(position) vec4<f32> {
+ return vec4<f32>();
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, Expression) {
+ auto* src = R"(
+fn foo() -> i32 {
+ return (1 + (2 * 4)) - (3 * 5);
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ return -6i;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, Abstract) {
+ auto* src = R"(
+fn foo() {
+ const v = vec4(1, 2, 3, vec3(0)[1 + 1 - 0]);
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ const v = vec4(1, 2, 3, 0);
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, IndexExpression) {
+ auto* src = R"(
+struct S {
+ a : array<i32>,
+}
+
+@group(0) @binding(0) var<storage> s : S;
+
+fn foo() -> i32 {
+ return s.a[(3 * 5) - (1 + (2 * 4))];
+}
+)";
+
+ auto* expect = R"(
+struct S {
+ a : array<i32>,
+}
+
+@group(0i) @binding(0i) var<storage> s : S;
+
+fn foo() -> i32 {
+ return s.a[6i];
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, IndexAccessorToConst) {
+ auto* src = R"(
+const a : array<i32, 4> = array(0, 1, 2, 3);
+
+fn foo() -> i32 {
+ return a[3];
+}
+)";
+
+ auto* expect = R"(
+const a : array<i32, 4i> = array<i32, 4u>(0i, 1i, 2i, 3i);
+
+fn foo() -> i32 {
+ return 3i;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, SplatParam) {
+ auto* src = R"(
+fn foo() -> i32 {
+ let v = vec3(2 + 5 - 4);
+ return v.x;
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ let v = vec3<i32>(3i);
+ return v.x;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, CallParam) {
+ auto* src = R"(
+fn foo() -> i32 {
+ let v = vec3(2 + 5 - 4, 5 * 9, -2 + -3);
+ return v.x;
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ let v = vec3<i32>(3i, 45i, -5i);
+ return v.x;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, LHSIndexExpressionOnAssign) {
+ auto* src = R"(
+fn foo() -> i32 {
+ var v = vec4(0);
+ v[1 * 2 + (3 - 2)] = 1;
+
+ return v[1];
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ var v = vec4<i32>();
+ v[3i] = 1i;
+ return v[1i];
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, LHSIndexExpressionOnCompoundAssign) {
+ auto* src = R"(
+fn foo() -> i32 {
+ var v = vec4(0);
+ v[1 * 2 + (3 - 2)] += 1;
+
+ return v[1];
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ var v = vec4<i32>();
+ v[3i] += 1i;
+ return v[1i];
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, LHSIndexExpressionOnIncrement) {
+ auto* src = R"(
+fn foo() -> i32 {
+ var v = vec4(0);
+ v[1 * 2 + (3 - 2)]++;
+
+ return v[1];
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> i32 {
+ var v = vec4<i32>();
+ v[3i]++;
+ return v[1i];
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, Attribute) {
+ auto* src = R"(
+struct A {
+ @location(1 + 2)
+ v : i32,
+}
+
+@group(0) @binding(0) var<storage> a : A;
+
+fn foo() -> i32 {
+ return a.v;
+}
+)";
+
+ auto* expect = R"(
+struct A {
+ @location(3i)
+ v : i32,
+}
+
+@group(0i) @binding(0i) var<storage> a : A;
+
+fn foo() -> i32 {
+ return a.v;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, ShortCircut) {
+ auto* src = R"(
+fn foo() -> bool {
+ return false && (1 + 2) == 3;
+}
+)";
+
+ auto* expect = R"(
+fn foo() -> bool {
+ return false;
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, BreakIf) {
+ auto* src = R"(
+fn foo() {
+ loop {
+
+ continuing {
+ break if 4 > 3;
+ }
+ }
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ loop {
+
+ continuing {
+ break if true;
+ }
+ }
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, Switch) {
+ auto* src = R"(
+fn foo() {
+ switch(1 + 2 + (3 * 5)) {
+ case 1 + 2, 3 + 4: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ switch(18i) {
+ case 3i, 7i: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, If) {
+ auto* src = R"(
+fn foo() {
+ if 4 - 2 > 3 {
+ return;
+ }
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ if (false) {
+ return;
+ }
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, For) {
+ auto* src = R"(
+fn foo() {
+ for(var i = 2 + (3 * 4); i < 9 + (5 * 10); i = i + (2 * 3)) {
+ }
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ for(var i = 14i; (i < 59i); i = (i + 6i)) {
+ }
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, While) {
+ auto* src = R"(
+fn foo() {
+ while(2 > 4) {
+ }
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ while(false) {
+ }
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, ConstAssert) {
+ auto* src = R"(
+const_assert 2 < (3 + 5);
+)";
+
+ auto* expect = R"(
+const_assert true;
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(FoldConstantsTest, InternalStruct) {
+ auto* src = R"(
+fn foo() {
+ let a = modf(1.5);
+}
+)";
+
+ auto* expect = R"(
+fn foo() {
+ let a = __modf_result_f32(0.5f, 1.0f);
+}
+)";
+
+ auto got = Run<FoldConstants>(src);
+ EXPECT_EQ(expect, str(got));
+}
+
+} // namespace
+} // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before.cc b/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before.cc
index f1fa3d8..4c9cd1b 100644
--- a/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before.cc
+++ b/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before.cc
@@ -29,16 +29,13 @@
#include <utility>
-#include "src/tint/lang/core/type/reference.h"
#include "src/tint/lang/wgsl/ast/builder.h"
#include "src/tint/lang/wgsl/program/clone_context.h"
#include "src/tint/lang/wgsl/sem/block_statement.h"
#include "src/tint/lang/wgsl/sem/for_loop_statement.h"
#include "src/tint/lang/wgsl/sem/if_statement.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
#include "src/tint/lang/wgsl/sem/while_statement.h"
#include "src/tint/utils/containers/hashmap.h"
-#include "src/tint/utils/containers/reverse.h"
#include "src/tint/utils/containers/transform.h"
namespace tint::ast::transform {
diff --git a/src/tint/lang/wgsl/ast/transform/std140.cc b/src/tint/lang/wgsl/ast/transform/std140.cc
index 9dc49b5..42fb0f9 100644
--- a/src/tint/lang/wgsl/ast/transform/std140.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140.cc
@@ -456,6 +456,8 @@
uint32_t size) {
// Replace the member with column vectors.
const auto num_columns = mat->columns();
+ const auto column_size = mat->ColumnType()->Size();
+ const auto column_stride = mat->ColumnStride();
// Build a struct member for each column of the matrix
tint::Vector<const StructMember*, 4> out;
for (uint32_t i = 0; i < num_columns; i++) {
@@ -466,10 +468,13 @@
// needs to be applied to the first column vector.
attributes.Push(b.MemberAlign(i32(align)));
}
- if ((i == num_columns - 1) && mat->Size() != size) {
- // The matrix was @size() annotated with a larger size than the
- // natural size for the matrix. This extra padding needs to be
- // applied to the last column vector.
+ if ((i == num_columns - 1) &&
+ (column_stride * (num_columns - 1) + column_size) != size) {
+ // The matrix size is larger than the individual component vectors.
+ // This occurs with matNx3 matrices, as the last vec3 column has space for one extra
+ // trailing scalar, which is occupied by the matrix. It also applies to matrices
+ // with an explicit @size() attribute.
+ // Apply extra padding needs to the last column vector.
attributes.Push(
b.MemberSize(AInt(size - mat->ColumnType()->Align() * (num_columns - 1))));
}
diff --git a/src/tint/lang/wgsl/ast/transform/std140_exhaustive_test.cc b/src/tint/lang/wgsl/ast/transform/std140_exhaustive_test.cc
index f9dca89..18e722f 100644
--- a/src/tint/lang/wgsl/ast/transform/std140_exhaustive_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140_exhaustive_test.cc
@@ -80,11 +80,11 @@
}
// For each column, replaces "${col_id_for_tmpl}" by column index in `tmpl` to get a string, and
- // join all these strings with `seperator`. If `tmpl_for_last_column` is not empty, use it
+ // join all these strings with `separator`. If `tmpl_for_last_column` is not empty, use it
// instead of `tmpl` for the last column.
std::string JoinTemplatedStringForEachMatrixColumn(
std::string tmpl,
- std::string seperator,
+ std::string separator,
std::string tmpl_for_last_column = "") const {
std::string result;
if (tmpl_for_last_column.size() == 0) {
@@ -92,13 +92,13 @@
}
for (size_t c = 0; c < columns - 1; c++) {
if (c > 0) {
- result += seperator;
+ result += separator;
}
std::string string_for_current_column =
tint::ReplaceAll(tmpl, "${col_id_for_tmpl}", std::to_string(c));
result += string_for_current_column;
}
- result += seperator;
+ result += separator;
std::string string_for_last_column = tint::ReplaceAll(
tmpl_for_last_column, "${col_id_for_tmpl}", std::to_string(columns - 1));
result += string_for_last_column;
@@ -106,13 +106,17 @@
}
std::string ExpendedColumnVectors(uint32_t leading_space, std::string name) const {
+ if (rows == 3) {
+ return ExpendedColumnVectorsWithLastSize(leading_space, name,
+ type == MatrixType::f16 ? 8 : 16);
+ }
std::string space(leading_space, ' ');
return JoinTemplatedStringForEachMatrixColumn(
space + name + "${col_id_for_tmpl} : " + ColumnVector() + ",", "\n");
}
- std::string ExpendedColumnVectorsInline(std::string name, std::string seperator) const {
- return JoinTemplatedStringForEachMatrixColumn(name + "${col_id_for_tmpl}", seperator);
+ std::string ExpendedColumnVectorsInline(std::string name, std::string separator) const {
+ return JoinTemplatedStringForEachMatrixColumn(name + "${col_id_for_tmpl}", separator);
}
std::string ExpendedColumnVectorsWithLastSize(uint32_t leading_space,
diff --git a/src/tint/lang/wgsl/ast/transform/std140_f16_test.cc b/src/tint/lang/wgsl/ast/transform/std140_f16_test.cc
index 43ddf38..7c17213 100644
--- a/src/tint/lang/wgsl/ast/transform/std140_f16_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140_f16_test.cc
@@ -121,6 +121,7 @@
struct S2x3F16_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -131,6 +132,7 @@
struct S3x3F16_std140 {
m_0 : vec3<f16>,
m_1 : vec3<f16>,
+ @size(8)
m_2 : vec3<f16>,
}
@@ -142,6 +144,7 @@
m_0 : vec3<f16>,
m_1 : vec3<f16>,
m_2 : vec3<f16>,
+ @size(8)
m_3 : vec3<f16>,
}
@@ -223,6 +226,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -262,6 +266,7 @@
before : i32,
@align(128i)
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
after : i32,
}
@@ -380,6 +385,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -426,6 +432,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -461,6 +468,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -493,6 +501,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -539,6 +548,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -571,6 +581,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -617,6 +628,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -649,6 +661,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -696,6 +709,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -729,6 +743,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -782,6 +797,7 @@
struct S_std140 {
m_1 : i32,
m__0 : vec3<f16>,
+ @size(8)
m__1 : vec3<f16>,
}
@@ -817,6 +833,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -860,6 +877,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -904,6 +922,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -944,6 +963,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -998,6 +1018,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -1038,6 +1059,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -1093,6 +1115,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -1134,6 +1157,7 @@
struct S_std140 {
m_0 : vec3<f16>,
+ @size(8)
m_1 : vec3<f16>,
}
@@ -2294,6 +2318,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2337,6 +2362,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2373,6 +2399,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2409,6 +2436,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2441,6 +2469,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2474,6 +2503,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2522,6 +2552,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2572,6 +2603,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2631,6 +2663,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2686,6 +2719,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2734,6 +2768,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2783,6 +2818,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2828,6 +2864,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2874,6 +2911,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2934,6 +2972,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -2988,6 +3027,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3039,6 +3079,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3083,6 +3124,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3128,6 +3170,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3165,6 +3208,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3203,6 +3247,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3241,6 +3286,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3279,6 +3325,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3313,6 +3360,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3362,6 +3410,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3398,6 +3447,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3448,6 +3498,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3484,6 +3535,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3535,6 +3587,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
@@ -3573,6 +3626,7 @@
struct mat2x3_f16 {
col0 : vec3<f16>,
+ @size(8)
col1 : vec3<f16>,
}
diff --git a/src/tint/lang/wgsl/builtin_fn.cc b/src/tint/lang/wgsl/builtin_fn.cc
index a601143..78afd1b 100644
--- a/src/tint/lang/wgsl/builtin_fn.cc
+++ b/src/tint/lang/wgsl/builtin_fn.cc
@@ -752,6 +752,18 @@
case BuiltinFn::kAtomicStore:
case BuiltinFn::kAtomicSub:
case BuiltinFn::kAtomicXor:
+ case BuiltinFn::kDpdx:
+ case BuiltinFn::kDpdxCoarse:
+ case BuiltinFn::kDpdxFine:
+ case BuiltinFn::kDpdy:
+ case BuiltinFn::kDpdyCoarse:
+ case BuiltinFn::kDpdyFine:
+ case BuiltinFn::kFwidth:
+ case BuiltinFn::kFwidthCoarse:
+ case BuiltinFn::kFwidthFine:
+ case BuiltinFn::kTextureSample:
+ case BuiltinFn::kTextureSampleBias:
+ case BuiltinFn::kTextureSampleCompare:
case BuiltinFn::kTextureStore:
case BuiltinFn::kWorkgroupUniformLoad:
return true;
diff --git a/src/tint/lang/wgsl/builtin_fn.cc.tmpl b/src/tint/lang/wgsl/builtin_fn.cc.tmpl
index ee359d0..613a862 100644
--- a/src/tint/lang/wgsl/builtin_fn.cc.tmpl
+++ b/src/tint/lang/wgsl/builtin_fn.cc.tmpl
@@ -123,6 +123,18 @@
case BuiltinFn::kAtomicStore:
case BuiltinFn::kAtomicSub:
case BuiltinFn::kAtomicXor:
+ case BuiltinFn::kDpdx:
+ case BuiltinFn::kDpdxCoarse:
+ case BuiltinFn::kDpdxFine:
+ case BuiltinFn::kDpdy:
+ case BuiltinFn::kDpdyCoarse:
+ case BuiltinFn::kDpdyFine:
+ case BuiltinFn::kFwidth:
+ case BuiltinFn::kFwidthCoarse:
+ case BuiltinFn::kFwidthFine:
+ case BuiltinFn::kTextureSample:
+ case BuiltinFn::kTextureSampleBias:
+ case BuiltinFn::kTextureSampleCompare:
case BuiltinFn::kTextureStore:
case BuiltinFn::kWorkgroupUniformLoad:
return true;
diff --git a/src/tint/lang/wgsl/ls/BUILD.bazel b/src/tint/lang/wgsl/ls/BUILD.bazel
new file mode 100644
index 0000000..25ddd43
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.bazel
@@ -0,0 +1,179 @@
+# 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 = [
+ "cancel_request.cc",
+ "change_configuration.cc",
+ "definition.cc",
+ "diagnostics.cc",
+ "document.cc",
+ "file.cc",
+ "hover.cc",
+ "initialize.cc",
+ "inlay_hints.cc",
+ "references.cc",
+ "rename.cc",
+ "sem_tokens.cc",
+ "serve.cc",
+ "server.cc",
+ "set_trace.cc",
+ "signature_help.cc",
+ "symbols.cc",
+ ],
+ hdrs = [
+ "file.h",
+ "sem_token.h",
+ "serve.h",
+ "server.h",
+ "utils.h",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/type",
+ "//src/tint/lang/wgsl",
+ "//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/common",
+ "//src/tint/lang/wgsl/features",
+ "//src/tint/lang/wgsl/intrinsic",
+ "//src/tint/lang/wgsl/program",
+ "//src/tint/lang/wgsl/sem",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+
+ ] + select({
+ ":tint_build_tintd": [
+
+ ],
+ "//conditions:default": [],
+ }) + select({
+ ":tint_build_wgsl_reader": [
+ "//src/tint/lang/wgsl/reader",
+ ],
+ "//conditions:default": [],
+ }),
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "definition_test.cc",
+ "diagnostics_test.cc",
+ "helpers_test.cc",
+ "helpers_test.h",
+ "hover_test.cc",
+ "inlay_hints_test.cc",
+ "references_test.cc",
+ "rename_test.cc",
+ "sem_tokens_test.cc",
+ "signature_help_test.cc",
+ "symbols_test.cc",
+ ],
+ deps = [
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/type",
+ "//src/tint/lang/wgsl",
+ "//src/tint/lang/wgsl/ast",
+ "//src/tint/lang/wgsl/program",
+ "//src/tint/lang/wgsl/sem",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ] + 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"],
+)
+
+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..611c64d
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.cmake
@@ -0,0 +1,173 @@
+# 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/cancel_request.cc
+ lang/wgsl/ls/change_configuration.cc
+ lang/wgsl/ls/definition.cc
+ lang/wgsl/ls/diagnostics.cc
+ lang/wgsl/ls/document.cc
+ lang/wgsl/ls/file.cc
+ lang/wgsl/ls/file.h
+ lang/wgsl/ls/hover.cc
+ lang/wgsl/ls/initialize.cc
+ lang/wgsl/ls/inlay_hints.cc
+ lang/wgsl/ls/references.cc
+ lang/wgsl/ls/rename.cc
+ lang/wgsl/ls/sem_token.h
+ lang/wgsl/ls/sem_tokens.cc
+ lang/wgsl/ls/serve.cc
+ lang/wgsl/ls/serve.h
+ lang/wgsl/ls/server.cc
+ lang/wgsl/ls/server.h
+ lang/wgsl/ls/set_trace.cc
+ lang/wgsl/ls/signature_help.cc
+ lang/wgsl/ls/symbols.cc
+ lang/wgsl/ls/utils.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_ls lib
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_lang_wgsl
+ tint_lang_wgsl_ast
+ tint_lang_wgsl_common
+ tint_lang_wgsl_features
+ tint_lang_wgsl_intrinsic
+ tint_lang_wgsl_program
+ tint_lang_wgsl_sem
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ 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)
+
+if(TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_lang_wgsl_ls lib
+ tint_lang_wgsl_reader
+ )
+endif(TINT_BUILD_WGSL_READER)
+
+endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+if(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+################################################################################
+# Target: tint_lang_wgsl_ls_test
+# Kind: test
+# Condition: TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER
+################################################################################
+tint_add_target(tint_lang_wgsl_ls_test test
+ lang/wgsl/ls/definition_test.cc
+ lang/wgsl/ls/diagnostics_test.cc
+ lang/wgsl/ls/helpers_test.cc
+ lang/wgsl/ls/helpers_test.h
+ lang/wgsl/ls/hover_test.cc
+ lang/wgsl/ls/inlay_hints_test.cc
+ lang/wgsl/ls/references_test.cc
+ lang/wgsl/ls/rename_test.cc
+ lang/wgsl/ls/sem_tokens_test.cc
+ lang/wgsl/ls/signature_help_test.cc
+ lang/wgsl/ls/symbols_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_ls_test test
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_type
+ tint_lang_wgsl
+ tint_lang_wgsl_ast
+ tint_lang_wgsl_program
+ tint_lang_wgsl_sem
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_wgsl_ls_test test
+ "gtest"
+)
+
+if(TINT_BUILD_TINTD)
+ tint_target_add_external_dependencies(tint_lang_wgsl_ls_test test
+ "langsvr"
+ )
+endif(TINT_BUILD_TINTD)
+
+if(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+ tint_target_add_dependencies(tint_lang_wgsl_ls_test test
+ tint_lang_wgsl_ls
+ )
+endif(TINT_BUILD_TINTD AND TINT_BUILD_WGSL_READER)
+
+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..6dde581
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/BUILD.gn
@@ -0,0 +1,158 @@
+# 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_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+if (tint_build_tintd && tint_build_wgsl_reader) {
+ libtint_source_set("ls") {
+ sources = [
+ "cancel_request.cc",
+ "change_configuration.cc",
+ "definition.cc",
+ "diagnostics.cc",
+ "document.cc",
+ "file.cc",
+ "file.h",
+ "hover.cc",
+ "initialize.cc",
+ "inlay_hints.cc",
+ "references.cc",
+ "rename.cc",
+ "sem_token.h",
+ "sem_tokens.cc",
+ "serve.cc",
+ "serve.h",
+ "server.cc",
+ "server.h",
+ "set_trace.cc",
+ "signature_help.cc",
+ "symbols.cc",
+ "utils.h",
+ ]
+ deps = [
+ "${tint_src_dir}:thread",
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/common",
+ "${tint_src_dir}/lang/wgsl/features",
+ "${tint_src_dir}/lang/wgsl/intrinsic",
+ "${tint_src_dir}/lang/wgsl/program",
+ "${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+
+ if (tint_build_tintd) {
+ deps += [ "${tint_src_dir}:langsvr" ]
+ }
+
+ if (tint_build_wgsl_reader) {
+ deps += [ "${tint_src_dir}/lang/wgsl/reader" ]
+ }
+ }
+}
+if (tint_build_unittests) {
+ if (tint_build_tintd && tint_build_wgsl_reader) {
+ tint_unittests_source_set("unittests") {
+ sources = [
+ "definition_test.cc",
+ "diagnostics_test.cc",
+ "helpers_test.cc",
+ "helpers_test.h",
+ "hover_test.cc",
+ "inlay_hints_test.cc",
+ "references_test.cc",
+ "rename_test.cc",
+ "sem_tokens_test.cc",
+ "signature_help_test.cc",
+ "symbols_test.cc",
+ ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/wgsl",
+ "${tint_src_dir}/lang/wgsl/ast",
+ "${tint_src_dir}/lang/wgsl/program",
+ "${tint_src_dir}/lang/wgsl/sem",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${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/lang/wgsl/ls/cancel_request.cc b/src/tint/lang/wgsl/ls/cancel_request.cc
new file mode 100644
index 0000000..1fb6f08
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/cancel_request.cc
@@ -0,0 +1,39 @@
+// 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 "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(const lsp::CancelRequestNotification&) {
+ return langsvr::Success;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/change_configuration.cc b/src/tint/lang/wgsl/ls/change_configuration.cc
new file mode 100644
index 0000000..430a914
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/change_configuration.cc
@@ -0,0 +1,40 @@
+// 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 "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(
+ const lsp::WorkspaceDidChangeConfigurationNotification&) {
+ return langsvr::Success;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/definition.cc b/src/tint/lang/wgsl/ls/definition.cc
new file mode 100644
index 0000000..d20b269
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/definition.cc
@@ -0,0 +1,52 @@
+// 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 "src/tint/lang/wgsl/ls/utils.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+typename lsp::TextDocumentDefinitionRequest::ResultType //
+Server::Handle(const lsp::TextDocumentDefinitionRequest& r) {
+ typename lsp::TextDocumentDefinitionRequest::SuccessType result = lsp::Null{};
+
+ if (auto file = files_.Get(r.text_document.uri)) {
+ if (auto def = (*file)->Definition(Conv(r.position))) {
+ lsp::Location loc;
+ loc.range = Conv(def->definition);
+ loc.uri = r.text_document.uri;
+ result = lsp::Definition{loc};
+ }
+ }
+
+ return result;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/definition_test.cc b/src/tint/lang/wgsl/ls/definition_test.cc
new file mode 100644
index 0000000..f9d9780
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/definition_test.cc
@@ -0,0 +1,175 @@
+// 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 <gtest/gtest.h>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+#include "src/tint/utils/text/unicode.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+using LsDefinitionTest = LsTestWithParam<std::string_view>;
+TEST_P(LsDefinitionTest, Definition) {
+ auto parsed = ParseMarkers(GetParam());
+ ASSERT_EQ(parsed.positions.size(), 1u);
+ ASSERT_LE(parsed.ranges.size(), 1u);
+
+ lsp::TextDocumentDefinitionRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+ req.position = parsed.positions[0];
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.ranges.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<lsp::Definition>());
+ auto definition = *res.Get<lsp::Definition>();
+ ASSERT_TRUE(definition.Is<lsp::Location>());
+ EXPECT_THAT(definition.Get<lsp::Location>()->uri, req.text_document.uri);
+ EXPECT_THAT(definition.Get<lsp::Location>()->range, parsed.ranges[0]);
+ }
+}
+
+// TODO(bclayton): Type aliases.
+INSTANTIATE_TEST_SUITE_P(,
+ LsDefinitionTest,
+ ::testing::ValuesIn(std::vector<std::string_view>{
+ R"(
+const「CONST」= 42;
+fn f() { _ = ⧘CONST; }
+)", // =========================================
+ R"(
+var<private>「VAR」= 42;
+fn f() { _ = V⧘AR; }
+)", // =========================================
+ R"(
+override「OVERRIDE」= 42;
+fn f() { _ = OVERRID⧘E; }
+)", // =========================================
+ R"(
+struct「STRUCT」{ i : i32 }
+fn f(s : ⧘STRUCT) {}
+)", // =========================================
+ R"(
+struct S {「i」: i32 }
+fn f(s : S) { _ = s.⧘i; }
+)", // =========================================
+ R"(
+fn f(「p」: i32) { _ = ⧘p; }
+)", // =========================================
+ R"(
+fn f() {
+ const「i」= 42;
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+fn f() {
+ let「i」= 42;
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+fn f() {
+ var「i」= 42;
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+fn f() {
+ var i = 42;
+ {
+ var「i」= 42;
+ _ = ⧘i;
+ }
+}
+)", // =========================================
+ R"(
+fn f() {
+ var「i」= 42;
+ {
+ var i = 42;
+ }
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+const i = 42;
+fn f() {
+ var「i」= 42;
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+const i = 42;
+fn f(「i」: i32) {
+ _ = ⧘i;
+}
+)", // =========================================
+ R"(
+fn「a」() {}
+fn b() { ⧘a(); }
+)", // =========================================
+ R"(
+fn b() { ⧘a(); }
+fn「a」() {}
+)", // =========================================
+ R"(
+fn f() {
+ let「i」= 42;
+ _ = (max(i⧘, 8) * 5);
+}
+)", // =========================================
+ R"(
+const C = m⧘ax(1, 2);
+)", // =========================================
+ R"(
+const C : i⧘32 = 42;
+)"}));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/diagnostics.cc b/src/tint/lang/wgsl/ls/diagnostics.cc
new file mode 100644
index 0000000..c4d0a90
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/diagnostics.cc
@@ -0,0 +1,63 @@
+// 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"
+#include "src/tint/lang/wgsl/ls/utils.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::PublishDiagnostics(File& file) {
+ lsp::TextDocumentPublishDiagnosticsNotification out;
+ out.uri = file.source->path;
+ for (auto& diag : file.program.Diagnostics()) {
+ lsp::Diagnostic d;
+ d.message = diag.message.Plain();
+ d.range = Conv(diag.source.range);
+ switch (diag.severity) {
+ case diag::Severity::Note:
+ d.severity = lsp::DiagnosticSeverity::kInformation;
+ break;
+ case diag::Severity::Warning:
+ d.severity = lsp::DiagnosticSeverity::kWarning;
+ break;
+ case diag::Severity::Error:
+ case diag::Severity::InternalCompilerError:
+ case diag::Severity::Fatal:
+ d.severity = lsp::DiagnosticSeverity::kError;
+ break;
+ }
+ out.diagnostics.push_back(std::move(d));
+ }
+
+ return session_.Send(out);
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/diagnostics_test.cc b/src/tint/lang/wgsl/ls/diagnostics_test.cc
new file mode 100644
index 0000000..4bb9d53
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/diagnostics_test.cc
@@ -0,0 +1,120 @@
+// 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 <string>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ const std::string_view wgsl;
+ const std::vector<lsp::Diagnostic> diagnostics;
+};
+
+struct Diagnostic : lsp::Diagnostic {
+ explicit Diagnostic(std::string_view msg) { message = msg; }
+
+ Diagnostic& Range(lsp::Uinteger start_line,
+ lsp::Uinteger start_column,
+ lsp::Uinteger end_line,
+ lsp::Uinteger end_column) {
+ range = lsp::Range{{start_line, start_column}, {end_line, end_column}};
+ return *this;
+ }
+ Diagnostic& Severity(lsp::DiagnosticSeverity s) {
+ severity = s;
+ return *this;
+ }
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.wgsl << "'";
+}
+
+using LsDiagnosticsTest = LsTestWithParam<Case>;
+TEST_P(LsDiagnosticsTest, Diagnostics) {
+ lsp::TextDocumentDocumentSymbolRequest req{};
+ req.text_document.uri = OpenDocument(GetParam().wgsl);
+ ASSERT_EQ(diagnostics_.Length(), 1u);
+ auto& notification = diagnostics_[0];
+ EXPECT_EQ(notification.uri, req.text_document.uri);
+ EXPECT_THAT(notification.diagnostics, testing::ContainerEq(GetParam().diagnostics));
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ LsDiagnosticsTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ "",
+ {},
+ },
+ {
+ "unknown_symbol",
+ {
+ Diagnostic{"unexpected token"}
+ .Range(0, 0, 0, 14)
+ .Severity(lsp::DiagnosticSeverity::kError),
+ },
+ },
+ {
+ "fn f() { return; return; }",
+ {
+ Diagnostic{"code is unreachable"}
+ .Range(0, 17, 0, 23)
+ .Severity(lsp::DiagnosticSeverity::kWarning),
+ },
+ },
+ {
+ "const A = B; const B = A;",
+ {
+ Diagnostic{"cyclic dependency found: 'A' -> 'B' -> 'A'"}
+ .Range(0, 0, 0, 11)
+ .Severity(lsp::DiagnosticSeverity::kError),
+
+ Diagnostic{"const 'A' references const 'B' here"}
+ .Range(0, 10, 0, 11)
+ .Severity(lsp::DiagnosticSeverity::kInformation),
+
+ Diagnostic{"const 'B' references const 'A' here"}
+ .Range(0, 23, 0, 24)
+ .Severity(lsp::DiagnosticSeverity::kInformation),
+ },
+ },
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/document.cc b/src/tint/lang/wgsl/ls/document.cc
new file mode 100644
index 0000000..457c720
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/document.cc
@@ -0,0 +1,90 @@
+// 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 "src/tint/lang/wgsl/reader/reader.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+namespace {
+
+/// @returns the byte offsets of the start of all the lines in @p str.
+std::vector<size_t> LineOffsets(std::string_view str) {
+ std::vector<size_t> offsets;
+ offsets.push_back(0);
+ for (size_t i = 0, n = str.length(); i < n; i++) {
+ if (str[i] == '\n') {
+ offsets.push_back(i + 1);
+ }
+ }
+ return offsets;
+}
+
+} // namespace
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(
+ const lsp::TextDocumentDidOpenNotification& n) {
+ auto source = std::make_unique<Source::File>(n.text_document.uri, n.text_document.text);
+ auto program = wgsl::reader::Parse(source.get());
+ auto file =
+ std::make_shared<File>(std::move(source), n.text_document.version, std::move(program));
+ files_.Add(n.text_document.uri, file);
+ return PublishDiagnostics(*file);
+}
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(
+ const lsp::TextDocumentDidCloseNotification& n) {
+ files_.Remove(n.text_document.uri);
+ return langsvr::Success;
+}
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(
+ const lsp::TextDocumentDidChangeNotification& n) {
+ auto file = files_.Get(n.text_document.uri);
+ if (!file) {
+ return langsvr::Failure{"document not found"};
+ }
+
+ auto content = (*file)->source->content.data;
+ for (auto& change : n.content_changes) {
+ if (auto* edit = change.Get<lsp::TextDocumentContentChangePartial>()) {
+ std::vector<size_t> line_offsets = LineOffsets(content);
+ size_t start = line_offsets[edit->range.start.line] + edit->range.start.character;
+ size_t end = line_offsets[edit->range.end.line] + edit->range.end.character;
+ content = content.substr(0, start) + edit->text + content.substr(end);
+ }
+ }
+ auto source = std::make_unique<Source::File>(n.text_document.uri, content);
+ auto program = wgsl::reader::Parse(source.get());
+ *file = std::make_shared<File>(std::move(source), n.text_document.version, std::move(program));
+ return PublishDiagnostics(**file);
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/file.cc b/src/tint/lang/wgsl/ls/file.cc
new file mode 100644
index 0000000..223eb8f
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/file.cc
@@ -0,0 +1,196 @@
+// 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 <optional>
+#include <utility>
+
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/identifier_expression.h"
+#include "src/tint/lang/wgsl/ast/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/ls/file.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/function.h"
+#include "src/tint/lang/wgsl/sem/function_expression.h"
+#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/sem/struct.h"
+#include "src/tint/lang/wgsl/sem/type_expression.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::wgsl::ls {
+
+File::File(std::unique_ptr<Source::File>&& source_, int64_t version_, Program program_)
+ : source(std::move(source_)), version(version_), program(std::move(program_)) {
+ nodes.reserve(program.ASTNodes().Count());
+ for (auto* node : program.ASTNodes().Objects()) {
+ nodes.push_back(node);
+ }
+ std::stable_sort(nodes.begin(), nodes.end(), [](const ast::Node* a, const ast::Node* b) {
+ if (a->source.range.begin < b->source.range.begin) {
+ return true;
+ }
+ if (a->source.range.begin > b->source.range.begin) {
+ return false;
+ }
+ if (a->source.range.end < b->source.range.end) {
+ return true;
+ }
+ if (a->source.range.end > b->source.range.end) {
+ return false;
+ }
+ return false;
+ });
+}
+
+std::vector<Source::Range> File::References(Source::Location l, bool include_declaration) {
+ std::vector<Source::Range> references;
+ auto variable_refs = [&](const sem::Variable* v) {
+ if (include_declaration) {
+ references.push_back(v->Declaration()->name->source.range);
+ }
+ for (auto* user : v->Users()) {
+ references.push_back(user->Declaration()->source.range);
+ }
+ };
+ auto function_refs = [&](const sem::Function* f) {
+ if (include_declaration) {
+ references.push_back(f->Declaration()->name->source.range);
+ }
+ for (auto* call : f->CallSites()) {
+ references.push_back(call->Declaration()->target->source.range);
+ }
+ };
+ auto struct_member = [&](const sem::StructMember* m) {
+ if (include_declaration) {
+ references.push_back(m->Declaration()->name->source.range);
+ }
+ for (auto* node : nodes) {
+ if (auto* access = program.Sem().Get<sem::StructMemberAccess>(node)) {
+ if (access->Member() == m) {
+ references.push_back(access->Declaration()->member->source.range);
+ }
+ }
+ }
+ };
+ auto struct_ = [&](const sem::Struct* s) {
+ if (include_declaration) {
+ references.push_back(s->Declaration()->name->source.range);
+ }
+ for (auto* node : nodes) {
+ if (auto* ident = node->As<ast::IdentifierExpression>()) {
+ if (auto* te = program.Sem().Get<sem::TypeExpression>(node)) {
+ if (te->Type() == s) {
+ references.push_back(ident->source.range);
+ }
+ }
+ }
+ }
+ };
+
+ Switch(
+ Unwrap(NodeAt<CastableBase>(l)), //
+ [&](const sem::VariableUser* v) { variable_refs(v->Variable()); },
+ [&](const sem::Variable* v) { variable_refs(v); },
+ [&](const sem::FunctionExpression* e) { function_refs(e->Function()); },
+ [&](const sem::Function* f) { function_refs(f); },
+ [&](const sem::StructMemberAccess* a) {
+ if (auto* member = a->Member()->As<sem::StructMember>()) {
+ struct_member(member);
+ }
+ },
+ [&](const sem::StructMember* m) { struct_member(m); },
+ [&](const sem::TypeExpression* te) {
+ return Switch(te->Type(), //
+ [&](const sem::Struct* s) { return struct_(s); });
+ });
+ return references;
+}
+
+std::optional<File::DefinitionResult> File::Definition(Source::Location l) {
+ return Switch<std::optional<DefinitionResult>>(
+ Unwrap(NodeAt<CastableBase>(l)), //
+ [&](const sem::VariableUser* u) {
+ auto* v = u->Variable();
+ return DefinitionResult{
+ v->Declaration()->name->symbol.Name(),
+ v->Declaration()->name->source.range,
+ u->Declaration()->source.range,
+ };
+ },
+ [&](const sem::Variable* v) {
+ return DefinitionResult{
+ v->Declaration()->name->symbol.Name(),
+ v->Declaration()->name->source.range,
+ v->Declaration()->name->source.range,
+ };
+ },
+ [&](const sem::FunctionExpression* e) {
+ auto* f = e->Function();
+ return DefinitionResult{
+ f->Declaration()->name->symbol.Name(),
+ f->Declaration()->name->source.range,
+ e->Declaration()->source.range,
+ };
+ },
+ [&](const sem::Function* f) {
+ return DefinitionResult{
+ f->Declaration()->name->symbol.Name(),
+ f->Declaration()->name->source.range,
+ f->Declaration()->name->source.range,
+ };
+ },
+ [&](const sem::StructMemberAccess* a) -> std::optional<DefinitionResult> {
+ if (auto* m = a->Member()->As<sem::StructMember>()) {
+ return DefinitionResult{
+ m->Declaration()->name->symbol.Name(),
+ m->Declaration()->name->source.range,
+ a->Declaration()->member->source.range,
+ };
+ }
+ return std::nullopt;
+ },
+ [&](const sem::StructMember* m) {
+ return DefinitionResult{
+ m->Declaration()->name->symbol.Name(),
+ m->Declaration()->name->source.range,
+ m->Declaration()->name->source.range,
+ };
+ },
+ [&](const sem::TypeExpression* te) {
+ return Switch<std::optional<DefinitionResult>>(
+ te->Type(), //
+ [&](const sem::Struct* s) {
+ return DefinitionResult{
+ s->Declaration()->name->symbol.Name(),
+ s->Declaration()->name->source.range,
+ te->Declaration()->source.range,
+ };
+ });
+ });
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/file.h b/src/tint/lang/wgsl/ls/file.h
new file mode 100644
index 0000000..7e6c367
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/file.h
@@ -0,0 +1,125 @@
+// 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_FILE_H_
+#define SRC_TINT_LANG_WGSL_LS_FILE_H_
+
+#include <limits>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "src/tint/lang/wgsl/ast/node.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/lang/wgsl/sem/expression.h"
+#include "src/tint/lang/wgsl/sem/load.h"
+#include "src/tint/lang/wgsl/sem/materialize.h"
+#include "src/tint/utils/diagnostic/source.h"
+
+namespace tint::wgsl::ls {
+
+/// File represents an open language-server WGSL file ("document").
+class File {
+ public:
+ /// The source file
+ std::unique_ptr<Source::File> source;
+ /// The current version of the file. Incremented with each change.
+ int64_t version = 0;
+ /// The parsed and resolved Program
+ Program program;
+ /// A source-ordered list of AST nodes.
+ std::vector<const ast::Node*> nodes;
+
+ /// Constructor
+ File(std::unique_ptr<Source::File>&& source_, int64_t version_, Program program_);
+
+ /// @returns all the references to the symbol at the location @p l in the file.
+ /// @param l the source location to lookup the symbol.
+ /// @param include_declaration if true, the declaration of @p l will be included in the returned
+ /// list.
+ std::vector<Source::Range> References(Source::Location l, bool include_declaration);
+
+ /// The result of Definition
+ struct DefinitionResult {
+ // The identifier text
+ std::string text;
+ // The source range of the definition identifier
+ Source::Range definition;
+ // The source range of the reference identifier
+ Source::Range reference;
+ };
+
+ /// @returns the definition of the symbol at the location @p l in the file.
+ std::optional<DefinitionResult> Definition(Source::Location l);
+
+ /// Behaviour of NodeAt()
+ enum class UnwrapMode {
+ /// NodeAt will Unwrap() the semantic node when searching for the template type.
+ kNoUnwrap,
+ /// NodeAt will not Unwrap() the semantic node when searching for the template type.
+ kUnwrap
+ };
+
+ // Default UnwrapMode is to unwrap, unless searching for a sem::Materialize or sem::Load
+ template <typename T>
+ static constexpr UnwrapMode DefaultUnwrapMode =
+ (std::is_same_v<T, sem::Materialize> || std::is_same_v<T, sem::Load>)
+ ? UnwrapMode::kNoUnwrap
+ : UnwrapMode::kUnwrap;
+
+ /// @returns the inner-most semantic node at the location @p l in the file.
+ /// @tparam T the type or subtype of the node to scan for.
+ template <typename T = sem::Node, UnwrapMode UNWRAP_MODE = DefaultUnwrapMode<T>>
+ const T* NodeAt(Source::Location l) const {
+ // TODO(bclayton): This is a brute-force search. Optimize.
+ size_t best_len = std::numeric_limits<uint32_t>::max();
+ const T* best_node = nullptr;
+ for (auto* node : nodes) {
+ if (node->source.range.begin.line == node->source.range.end.line &&
+ node->source.range.begin <= l && node->source.range.end >= l) {
+ auto* sem = program.Sem().Get(node);
+ if constexpr (UNWRAP_MODE == UnwrapMode::kUnwrap) {
+ sem = Unwrap(sem);
+ }
+ if (auto* cast = As<T, CastFlags::kDontErrorOnImpossibleCast>(sem)) {
+ size_t len = node->source.range.end.column - node->source.range.begin.column;
+ if (len < best_len) {
+ best_len = len;
+ best_node = cast;
+ }
+ }
+ }
+ }
+ return best_node;
+ }
+};
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_FILE_H_
diff --git a/src/tint/lang/wgsl/ls/helpers_test.cc b/src/tint/lang/wgsl/ls/helpers_test.cc
new file mode 100644
index 0000000..d996285
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/helpers_test.cc
@@ -0,0 +1,86 @@
+// 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/helpers_test.h"
+
+#include <utility>
+
+namespace tint::wgsl::ls {
+
+namespace lsp = langsvr::lsp;
+
+ParsedMarkers ParseMarkers(std::string_view str) {
+ std::stringstream clean;
+ lsp::Position current_position;
+ std::vector<langsvr::lsp::Position> positions;
+ std::vector<langsvr::lsp::Range> ranges;
+ std::optional<langsvr::lsp::Range> current_range;
+ while (!str.empty()) {
+ auto [codepoint, len] =
+ utf8::Decode(reinterpret_cast<const uint8_t*>(str.data()), str.length());
+ if (codepoint == 0 || len == 0) {
+ break;
+ }
+
+ switch (codepoint) {
+ case '\n':
+ current_position.line++;
+ current_position.character = 0;
+ clean << "\n";
+ break;
+ case U"「"[0]:
+ // Range start. Replace with ' '
+ current_position.character++;
+ current_range = lsp::Range{};
+ current_range->start = current_position;
+ clean << ' ';
+ break;
+ case U"」"[0]:
+ // Range end. Replace with ' '
+ if (current_range) {
+ current_range->end = current_position;
+ ranges.push_back(*current_range);
+ current_range.reset();
+ }
+ clean << ' ';
+ current_position.character++;
+ break;
+ case U"⧘"[0]:
+ // Position. Consume
+ positions.push_back(current_position);
+ break;
+ default:
+ clean << str.substr(0, len);
+ current_position.character++;
+ break;
+ }
+ str = str.substr(len);
+ }
+ return ParsedMarkers{std::move(ranges), std::move(positions), clean.str()};
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/helpers_test.h b/src/tint/lang/wgsl/ls/helpers_test.h
new file mode 100644
index 0000000..d98b7a2
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/helpers_test.h
@@ -0,0 +1,110 @@
+
+// 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_HELPERS_TEST_H_
+#define SRC_TINT_LANG_WGSL_LS_HELPERS_TEST_H_
+
+#include <string>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/result.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace tint::wgsl::ls {
+
+/// A helper base class for language-server tests.
+/// Provides a server and client session, and helpers for 'opening' WGSL documents.
+/// @note use LsTest or LsTestWithParam<T> instead of using this class directly.
+template <typename BASE>
+class LsTestImpl : public BASE {
+ public:
+ /// Constructor
+ /// Initializes the server and client sessions, forming a bi-directional message channel.
+ /// Registers a langsvr::lsp::TextDocumentPublishDiagnosticsNotification handler for the client
+ /// session, so that diagnostic notifications are added to #diagnostics_.
+ LsTestImpl() {
+ server_session_.SetSender(
+ [&](std::string_view msg) { return client_session_.Receive(msg); });
+ client_session_.SetSender(
+ [&](std::string_view msg) { return server_session_.Receive(msg); });
+
+ client_session_.Register(
+ [&](const langsvr::lsp::TextDocumentPublishDiagnosticsNotification& n) {
+ diagnostics_.Push(n);
+ return langsvr::Success;
+ });
+ }
+
+ /// Constructs a langsvr::lsp::TextDocumentDidOpenNotification from @p wgsl and a new, unique
+ /// URI, and sends this to the server via the #client_session_. Once the server has finished
+ /// processing the notification, the server will respond with a
+ /// langsvr::lsp::TextDocumentPublishDiagnosticsNotification, which is handled by the
+ /// #client_session_ and placed into #diagnostics_.
+ std::string OpenDocument(std::string_view wgsl) {
+ std::string uri = "document-" + std::to_string(next_document_id_++) + ".wgsl";
+ langsvr::lsp::TextDocumentDidOpenNotification notification{};
+ notification.text_document.text = wgsl;
+ notification.text_document.uri = uri;
+ auto res = client_session_.Send(notification);
+ EXPECT_EQ(res, langsvr::Success);
+ return uri;
+ }
+
+ langsvr::Session server_session_;
+ langsvr::Session client_session_;
+ Server server_{server_session_};
+ int next_document_id_ = 0;
+ Vector<langsvr::lsp::TextDocumentPublishDiagnosticsNotification, 4> diagnostics_;
+};
+
+using LsTest = LsTestImpl<testing::Test>;
+
+template <typename T>
+using LsTestWithParam = LsTestImpl<testing::TestWithParam<T>>;
+
+/// Result structure of ParseMarkers
+struct ParsedMarkers {
+ /// All parsed ranges, marked up with '「' and '」'. For example: `「my_range」`
+ std::vector<langsvr::lsp::Range> ranges;
+ /// All parsed positions, marked up with '⧘'. For example: `posi⧘tion`
+ std::vector<langsvr::lsp::Position> positions;
+ /// The string with all markup removed.
+ /// '「' and '」' are replaced with whitespace.
+ /// '⧘' are omitted with no replacement characters.
+ std::string clean;
+};
+
+/// ParseMarkers parses location and range markers from the string @p str.
+ParsedMarkers ParseMarkers(std::string_view str);
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_HELPERS_TEST_H_
diff --git a/src/tint/lang/wgsl/ls/hover.cc b/src/tint/lang/wgsl/ls/hover.cc
new file mode 100644
index 0000000..5ffbe47
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/hover.cc
@@ -0,0 +1,262 @@
+// 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 <string_view>
+#include "src/tint/lang/core/constant/scalar.h"
+#include "src/tint/lang/core/constant/splat.h"
+#include "src/tint/lang/core/constant/value.h"
+#include "src/tint/lang/core/type/void.h"
+#include "src/tint/lang/wgsl/ast/const.h"
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/identifier_expression.h"
+#include "src/tint/lang/wgsl/ast/let.h"
+#include "src/tint/lang/wgsl/ast/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/ast/override.h"
+#include "src/tint/lang/wgsl/ast/templated_identifier.h"
+#include "src/tint/lang/wgsl/ast/var.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/behavior.h"
+#include "src/tint/lang/wgsl/sem/builtin_enum_expression.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
+#include "src/tint/lang/wgsl/sem/call.h"
+#include "src/tint/lang/wgsl/sem/call_target.h"
+#include "src/tint/lang/wgsl/sem/function.h"
+#include "src/tint/lang/wgsl/sem/function_expression.h"
+#include "src/tint/lang/wgsl/sem/load.h"
+#include "src/tint/lang/wgsl/sem/materialize.h"
+#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/sem/struct.h"
+#include "src/tint/lang/wgsl/sem/type_expression.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/text/string_stream.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+namespace {
+
+lsp::MarkedStringWithLanguage WGSL(std::string wgsl) {
+ lsp::MarkedStringWithLanguage str;
+ str.language = "wgsl";
+ str.value = wgsl;
+ return str;
+}
+
+void PrintConstant(const core::constant::Value* val, StringStream& ss) {
+ Switch(
+ val, //
+ [&](const core::constant::Scalar<AInt>* s) { ss << s->value; },
+ [&](const core::constant::Scalar<AFloat>* s) { ss << s->value; },
+ [&](const core::constant::Scalar<bool>* s) { ss << s->value; },
+ [&](const core::constant::Scalar<f16>* s) { ss << s->value << "h"; },
+ [&](const core::constant::Scalar<f32>* s) { ss << s->value << "f"; },
+ [&](const core::constant::Scalar<i32>* s) { ss << s->value << "i"; },
+ [&](const core::constant::Scalar<u32>* s) { ss << s->value << "u"; },
+ [&](const core::constant::Splat* s) {
+ ss << s->Type()->FriendlyName() << "(";
+ PrintConstant(s->el, ss);
+ ss << ")";
+ },
+ [&](const core::constant::Composite* s) {
+ ss << s->Type()->FriendlyName() << "(";
+ for (size_t i = 0, n = s->elements.Length(); i < n; i++) {
+ if (i > 0) {
+ ss << ", ";
+ }
+ PrintConstant(s->elements[i], ss);
+ }
+ ss << ")";
+ });
+}
+
+void Variable(const sem::Variable* v, std::vector<lsp::MarkedString>& out) {
+ StringStream ss;
+ auto* kind = Switch(
+ v->Declaration(), //
+ [&](const ast::Var*) { return "var"; }, //
+ [&](const ast::Let*) { return "let"; }, //
+ [&](const ast::Const*) { return "const"; }, //
+ [&](const ast::Override*) { return "override"; });
+ if (kind) {
+ ss << kind << " ";
+ }
+ ss << v->Declaration()->name->symbol.NameView() << " : "
+ << v->Type()->UnwrapRef()->FriendlyName();
+
+ if (auto* init = v->Initializer()) {
+ if (auto* val = init->ConstantValue()) {
+ ss << " = ";
+ PrintConstant(val, ss);
+ }
+ }
+
+ out.push_back(WGSL(ss.str()));
+}
+
+void Function(const sem::Function* f, std::vector<lsp::MarkedString>& out) {
+ StringStream ss;
+ ss << "fn " << f->Declaration()->name->symbol.NameView();
+ ss << "(";
+ bool first = true;
+ for (auto* param : f->Parameters()) {
+ if (!first) {
+ ss << ", ";
+ }
+ first = false;
+ ss << param->Declaration()->name->symbol.NameView() << " : "
+ << param->Type()->FriendlyName();
+ }
+ ss << ")";
+ if (auto* ret = f->ReturnType(); !ret->Is<core::type::Void>()) {
+ ss << " -> " << ret->FriendlyName();
+ }
+ out.push_back(WGSL(ss.str()));
+}
+
+void Call(std::string_view name, const sem::Call* c, std::vector<lsp::MarkedString>& out) {
+ StringStream ss;
+ ss << name << "(";
+ bool first = true;
+ for (auto* param : c->Target()->Parameters()) {
+ if (!first) {
+ ss << ", ";
+ }
+ first = false;
+ if (auto* decl = param->Declaration()) {
+ ss << decl->name->symbol.NameView() << " : ";
+ } else if (auto usage = param->Usage(); usage != core::ParameterUsage::kNone) {
+ ss << param->Usage() << " : ";
+ }
+ ss << param->Type()->FriendlyName();
+ }
+ ss << ")";
+ if (auto* ret = c->Target()->ReturnType(); !ret->Is<core::type::Void>()) {
+ ss << " -> " << ret->FriendlyName();
+ }
+ out.push_back(WGSL(ss.str()));
+}
+
+void Constant(const core::constant::Value* val, std::vector<lsp::MarkedString>& out) {
+ StringStream ss;
+ PrintConstant(val, ss);
+ out.push_back(WGSL(ss.str()));
+}
+
+} // namespace
+
+typename lsp::TextDocumentHoverRequest::ResultType //
+Server::Handle(const lsp::TextDocumentHoverRequest& r) {
+ auto file = files_.Get(r.text_document.uri);
+ if (!file) {
+ return lsp::Null{};
+ }
+
+ auto* node = (*file)->NodeAt<CastableBase, File::UnwrapMode::kNoUnwrap>(Conv(r.position));
+ if (!node) {
+ return lsp::Null{};
+ }
+
+ std::vector<lsp::MarkedString> strings;
+
+ if (auto* materialize = node->As<sem::Materialize>()) {
+ if (auto* val = materialize->ConstantValue()) {
+ Constant(val, strings);
+ lsp::Hover hover;
+ hover.contents = std::move(strings);
+ hover.range = Conv(materialize->Declaration()->source.range);
+ return hover;
+ }
+ }
+
+ langsvr::Optional<lsp::Range> range;
+ Switch(
+ Unwrap(node), //
+ [&](const sem::VariableUser* user) {
+ Variable(user->Variable(), strings);
+ range = Conv(user->Declaration()->source.range);
+ },
+ [&](const sem::Variable* v) {
+ Variable(v, strings);
+ range = Conv(v->Declaration()->name->source.range);
+ },
+ [&](const sem::Call* c) {
+ Call(c->Declaration()->target->identifier->symbol.NameView(), c, strings);
+ range = Conv(c->Declaration()->target->source.range);
+ },
+ [&](const sem::FunctionExpression* expr) {
+ Function(expr->Function(), strings);
+ range = Conv(expr->Declaration()->source.range);
+ },
+ [&](const sem::BuiltinEnumExpression<wgsl::BuiltinFn>* fn) {
+ if (auto* call = (*file)->NodeAt<sem::Call>(Conv(r.position))) {
+ Call(str(fn->Value()), call, strings);
+ } else {
+ strings.push_back(WGSL(str(fn->Value())));
+ }
+ range = Conv(fn->Declaration()->source.range);
+ },
+ [&](const sem::TypeExpression* expr) {
+ Switch(
+ expr->Type(), //
+ [&](const sem::Struct* str) {
+ strings.push_back(WGSL("struct " + str->Name().Name()));
+ },
+ [&](Default) { strings.push_back(WGSL(expr->Type()->FriendlyName())); });
+ range = Conv(expr->Declaration()->source.range);
+ },
+ [&](const sem::StructMemberAccess* access) {
+ if (auto* member = access->Member()->As<sem::StructMember>()) {
+ StringStream ss;
+ ss << member->Declaration()->name->symbol.NameView() << " : "
+ << member->Type()->FriendlyName();
+ strings.push_back(WGSL(ss.str()));
+ range = Conv(access->Declaration()->member->source.range);
+ }
+ },
+ [&](const sem::ValueExpression* expr) {
+ if (auto* val = expr->ConstantValue()) {
+ Constant(val, strings);
+ range = Conv(expr->Declaration()->source.range);
+ }
+ });
+
+ if (strings.empty()) {
+ return lsp::Null{};
+ }
+
+ lsp::Hover hover;
+ hover.contents = std::move(strings);
+ hover.range = std::move(range);
+ return hover;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/hover_test.cc b/src/tint/lang/wgsl/ls/hover_test.cc
new file mode 100644
index 0000000..048d8da
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/hover_test.cc
@@ -0,0 +1,311 @@
+// 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 <gtest/gtest.h>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ std::string_view markup;
+ std::vector<lsp::MarkedString> expected;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+using LsHoverTest = LsTestWithParam<Case>;
+TEST_P(LsHoverTest, Hover) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.positions.size(), 1u);
+
+ lsp::TextDocumentHoverRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+ req.position = parsed.positions[0];
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (GetParam().expected.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ ASSERT_TRUE(parsed.ranges.empty());
+ } else {
+ ASSERT_TRUE(res.Is<lsp::Hover>());
+ auto& hover = *res.Get<lsp::Hover>();
+ ASSERT_EQ(parsed.ranges.size(), 1u);
+ ASSERT_TRUE(hover.range);
+ EXPECT_EQ(*hover.range, parsed.ranges[0]);
+ ASSERT_TRUE(hover.contents.Is<std::vector<lsp::MarkedString>>());
+ auto& marked_strings = *hover.contents.Get<std::vector<lsp::MarkedString>>();
+ EXPECT_THAT(marked_strings, testing::ContainerEq(GetParam().expected));
+ }
+}
+
+// TODO(bclayton): Type aliases.
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ LsHoverTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ R"(
+const CONST = 42;
+fn f() { _ =「⧘CONST」; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "const CONST : abstract-int = 42"},
+ },
+ },
+ // =========================================
+ {
+ R"(
+var<private> VAR = 42;
+fn f() { _ = 「V⧘AR」; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "var VAR : i32 = 42i"},
+ },
+ }, // =========================================
+ {
+ R"(
+override OVERRIDE = 42;
+fn f() { _ = 「OVERRID⧘E」 ; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "override OVERRIDE : i32 = 42i"},
+ },
+ }, // =========================================
+ {
+ R"(
+struct STRUCT { i : i32 }
+fn f(s : 「⧘STRUCT」 ) {}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "struct STRUCT"},
+ },
+ }, // =========================================
+ {
+ R"(
+struct S { i : i32 }
+fn f(s : S) { _ = s.「⧘i」 ; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "i : i32"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f(p : i32) { _ =「⧘p」 ; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "p : i32"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ const i = 42;
+ _ =「i⧘」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "const i : abstract-int = 42"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ let i = 42;
+ _ = 「⧘i」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "let i : i32 = 42i"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ var i = 10 + 32;
+ i =「i⧘」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "var i : i32 = 42i"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ var i = 10;
+ {
+ var i = 42;
+ i =「i⧘」;
+ }
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "var i : i32 = 42i"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ var i = 10.0;
+ {
+ var i = 42;
+ }
+ i =「i⧘」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "var i : f32 = 10.0f"},
+ },
+ }, // =========================================
+ {
+ R"(
+const i = 42;
+fn f() {
+ var i = 42u;
+ i =「⧘i」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "var i : u32 = 42u"},
+ },
+ }, // =========================================
+ {
+ R"(
+const i = 42;
+fn f(i : i32) {
+ _ =「i⧘」;
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "i : i32"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn a() {}
+fn b() { 「⧘a」(); }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "fn a()"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn b() { 「⧘a」(); }
+fn a() -> i32 { return 1; }
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "fn a() -> i32"},
+ },
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ _ = max(3f,「⧘5」);
+}
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "5.0f"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C =「m⧘ax」(1, 2);
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl",
+ "max(abstract-int, abstract-int) -> abstract-int"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C : 「i⧘32」 = 42;
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "i32"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C = 「1 ⧘+ 2」;
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "3"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C = 「(1 + 2) ⧘* 3」;
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "9"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C = (「1 +⧘ 2」) * 3;
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "3"},
+ },
+ }, // =========================================
+ {
+ R"(
+const C : f32 = 「(1 + 2) *⧘ 3」;
+)",
+ {
+ lsp::MarkedStringWithLanguage{"wgsl", "9.0f"},
+ },
+ },
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/initialize.cc b/src/tint/lang/wgsl/ls/initialize.cc
new file mode 100644
index 0000000..00a71bc
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/initialize.cc
@@ -0,0 +1,39 @@
+// 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 "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(const lsp::InitializedNotification&) {
+ return langsvr::Success;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/inlay_hints.cc b/src/tint/lang/wgsl/ls/inlay_hints.cc
new file mode 100644
index 0000000..6e3a76d
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/inlay_hints.cc
@@ -0,0 +1,93 @@
+// 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 "langsvr/lsp/primitives.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/ast/variable.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/struct.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+typename lsp::TextDocumentInlayHintRequest::ResultType //
+Server::Handle(const lsp::TextDocumentInlayHintRequest& r) {
+ auto file = files_.Get(r.text_document.uri);
+ if (!file) {
+ return lsp::Null{};
+ }
+
+ std::vector<lsp::InlayHint> hints;
+ auto& program = (*file)->program;
+ for (auto* decl : program.AST().TypeDecls()) {
+ if (auto* str = program.Sem().Get<sem::Struct>(decl)) {
+ if (!str->UsedAs(core::AddressSpace::kStorage) &&
+ !str->UsedAs(core::AddressSpace::kUniform)) {
+ continue;
+ }
+ for (auto* member : str->Members()) {
+ auto pos = Conv(member->Declaration()->name->source.range.begin);
+ auto add = [&](std::string text) {
+ lsp::InlayHint hint;
+ hint.position = pos;
+ hint.label = text;
+ hint.padding_left = true;
+ hint.padding_right = true;
+ hints.push_back(hint);
+ };
+ add("offset: " + std::to_string(member->Offset()));
+ add("size: " + std::to_string(member->Size()));
+ }
+ }
+ }
+
+ for (auto* node : program.ASTNodes().Objects()) {
+ if (auto* decl = node->As<ast::Variable>()) {
+ if (!decl->type) {
+ if (auto* variable = program.Sem().Get(decl); variable && variable->Type()) {
+ lsp::InlayHint hint;
+ hint.position = Conv(decl->name->source.range.end);
+ hint.label = " : " + variable->Type()->UnwrapRef()->FriendlyName();
+ hints.push_back(hint);
+ }
+ }
+ }
+ }
+
+ if (hints.empty()) {
+ return lsp::Null{};
+ }
+
+ return std::move(hints);
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/inlay_hints_test.cc b/src/tint/lang/wgsl/ls/inlay_hints_test.cc
new file mode 100644
index 0000000..454f38a
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/inlay_hints_test.cc
@@ -0,0 +1,184 @@
+// 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 <gtest/gtest.h>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Hint {
+ std::string_view label;
+ bool pad_left = false;
+ bool pad_right = false;
+};
+
+struct Case {
+ std::string_view markup;
+ std::vector<Hint> hints;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+using LsInlayHintsTest = LsTestWithParam<Case>;
+TEST_P(LsInlayHintsTest, InlayHints) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.ranges.size(), 0u);
+ ASSERT_EQ(parsed.positions.size(), GetParam().hints.size());
+
+ lsp::TextDocumentInlayHintRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.positions.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<std::vector<langsvr::lsp::InlayHint>>());
+ auto& got_hints = *res.Get<std::vector<lsp::InlayHint>>();
+ std::vector<lsp::InlayHint> expected_hints;
+ for (size_t i = 0; i < parsed.positions.size(); i++) {
+ auto& hint = GetParam().hints[i];
+ lsp::InlayHint expected{};
+ expected.position = parsed.positions[i];
+ expected.label = lsp::String{hint.label};
+ if (hint.pad_left) {
+ expected.padding_left = true;
+ }
+ if (hint.pad_right) {
+ expected.padding_right = true;
+ }
+ expected_hints.push_back(std::move(expected));
+ }
+ EXPECT_EQ(got_hints, expected_hints);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ LsInlayHintsTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ R"(
+const CONST⧘ = 42;
+)",
+ {
+ {
+ " : abstract-int",
+ },
+ },
+ }, // =========================================
+ {
+ R"(
+var<private> VAR⧘ = 42;
+)",
+ {
+ {
+ " : i32",
+ },
+ },
+ }, // =========================================
+ {
+ R"(
+override OVERRIDE⧘ = 42;
+)",
+ {
+ {
+ " : i32",
+ },
+ },
+ }, // =========================================
+ {
+ R"(
+struct STRUCT {
+ ⧘⧘a : i32,
+ @size(32) ⧘⧘b : i32,
+ ⧘⧘c : i32,
+}
+@group(0) @binding(0) var<storage> v : STRUCT;
+)",
+ {
+ {"offset: 0", /* pad_left */ true, /* pad_right */ true},
+ {"size: 4", /* pad_left */ true, /* pad_right */ true},
+
+ {"offset: 4", /* pad_left */ true, /* pad_right */ true},
+ {"size: 32", /* pad_left */ true, /* pad_right */ true},
+
+ {"offset: 36", /* pad_left */ true, /* pad_right */ true},
+ {"size: 4", /* pad_left */ true, /* pad_right */ true},
+ },
+ }, // =========================================
+ {
+ R"(
+struct STRUCT {
+ i : i32
+}
+)",
+ {},
+ }, // =========================================
+ {
+ R"(
+const CONST : i32 = 42;
+)",
+ {},
+ }, // =========================================
+ {
+ R"(
+var<private> VAR : f32 = 42;
+)",
+ {},
+ }, // =========================================
+ {
+ R"(
+override OVERRIDE : u32 = 42;
+)",
+ {},
+ }, // =========================================
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/references.cc b/src/tint/lang/wgsl/ls/references.cc
new file mode 100644
index 0000000..9eda4d6
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/references.cc
@@ -0,0 +1,57 @@
+// 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 "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+typename lsp::TextDocumentReferencesRequest::ResultType //
+Server::Handle(const lsp::TextDocumentReferencesRequest& r) {
+ typename lsp::TextDocumentReferencesRequest::SuccessType result = lsp::Null{};
+
+ if (auto file = files_.Get(r.text_document.uri)) {
+ std::vector<lsp::Location> out;
+ for (auto& ref : (*file)->References(Conv(r.position), r.context.include_declaration)) {
+ lsp::Location loc;
+ loc.range = Conv(ref);
+ loc.uri = r.text_document.uri;
+ out.push_back(std::move(loc));
+ }
+ if (!out.empty()) {
+ result = out;
+ }
+ }
+
+ return result;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/references_test.cc b/src/tint/lang/wgsl/ls/references_test.cc
new file mode 100644
index 0000000..df732ec
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/references_test.cc
@@ -0,0 +1,293 @@
+// 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 <gtest/gtest.h>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ bool include_declaration;
+ std::string_view markup;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+using LsReferencesTest = LsTestWithParam<Case>;
+TEST_P(LsReferencesTest, References) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.positions.size(), 1u);
+
+ lsp::TextDocumentReferencesRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+ req.context.include_declaration = GetParam().include_declaration;
+ req.position = parsed.positions[0];
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.ranges.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<std::vector<lsp::Location>>());
+ std::vector<lsp::Range> got_ranges;
+ for (auto& location : *res.Get<std::vector<lsp::Location>>()) {
+ EXPECT_EQ(location.uri, req.text_document.uri);
+ got_ranges.push_back(location.range);
+ }
+ EXPECT_THAT(got_ranges, testing::UnorderedElementsAreArray(parsed.ranges));
+ }
+}
+
+// TODO(bclayton): Type aliases.
+INSTANTIATE_TEST_SUITE_P(IncludeDeclaration,
+ LsReferencesTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {/* include_declaration */ true, R"(
+const「CONST」= 42;
+fn f() { _ =「⧘CONST」; }
+const C =「CONST」;
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+var<private>「VAR」= 42;
+fn f() { _ =「V⧘AR」; }
+fn g() { _ = 「VAR」; }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+override「OVERRIDE」= 42;
+fn f() { _ =「OVERRID⧘E」+「OVERRIDE」; }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+struct「STRUCT」{ i : i32 }
+fn f(s :「⧘STRUCT」) { var v : 「STRUCT」; }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+struct S {「i」: i32 }
+fn f(s : S) { _ = s.「⧘i」; }
+fn g(s : S) { _ = s.「i」; }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f(「p」: i32) { _ =「⧘p」* 「p」; }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ const「i」= 42;
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ let「i」= 42;
+ _ =「⧘i」+「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ var「i」= 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ var i = 42;
+ {
+ var「i」= 42;
+ 「i」=「⧘i」;
+ }
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ var「i」= 42;
+ {
+ var i = 42;
+ }
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+const i = 42;
+fn f() {
+ var「i」= 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+const i = 42;
+fn f(「i」: i32) {
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn「a」() {}
+fn b() { 「⧘a」(); }
+fn c() { 「a」(); }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn b() { 「a⧘」(); }
+fn「a」() {}
+fn c() { 「a」(); }
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+fn f() {
+ let「i」= 42;
+ _ = (max(「i⧘」, 「i」) * 「i」);
+}
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+const C = m⧘ax(1, 2);
+)"}, // =========================================
+ {/* include_declaration */ true, R"(
+const C : i⧘32 = 42;
+)"},
+ }));
+
+INSTANTIATE_TEST_SUITE_P(ExcludeDeclaration,
+ LsReferencesTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {/* include_declaration */ false, R"(
+const CONST = 42;
+fn f() { _ =「⧘CONST」; }
+const C =「CONST」;
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+var<private> VAR = 42;
+fn f() { _ =「V⧘AR」; }
+fn g() { _ = 「VAR」; }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+override OVERRIDE = 42;
+fn f() { _ =「OVERRID⧘E」+「OVERRIDE」; }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+struct STRUCT { i : i32 }
+fn f(s :「⧘STRUCT」) { var v : 「STRUCT」; }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+struct S { i : i32 }
+fn f(s : S) { _ = s.「⧘i」; }
+fn g(s : S) { _ = s.「i」; }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f( p : i32) { _ =「⧘p」* 「p」; }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ const i = 42;
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ let i = 42;
+ _ =「⧘i」+「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ var i = 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ var i = 42;
+ {
+ var i = 42;
+ 「i」=「⧘i」;
+ }
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ var i = 42;
+ {
+ var i = 42;
+ }
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+const i = 42;
+fn f() {
+ var i = 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+const i = 42;
+fn f( i : i32) {
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn a() {}
+fn b() { 「⧘a」(); }
+fn c() { 「a」(); }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn b() { 「a⧘」(); }
+fn a() {}
+fn c() { 「a」(); }
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+fn f() {
+ let i = 42;
+ _ = (max(「i⧘」, 「i」) * 「i」);
+}
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+const C = m⧘ax(1, 2);
+)"}, // =========================================
+ {/* include_declaration */ false, R"(
+const C : i⧘32 = 42;
+)"},
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/rename.cc b/src/tint/lang/wgsl/ls/rename.cc
new file mode 100644
index 0000000..4cf5447
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/rename.cc
@@ -0,0 +1,95 @@
+// 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/lsp/primitives.h"
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/identifier_expression.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/function.h"
+#include "src/tint/lang/wgsl/sem/function_expression.h"
+#include "src/tint/lang/wgsl/sem/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/sem/struct.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+typename lsp::TextDocumentPrepareRenameRequest::ResultType //
+Server::Handle(const lsp::TextDocumentPrepareRenameRequest& r) {
+ typename lsp::TextDocumentPrepareRenameRequest::SuccessType result = lsp::Null{};
+
+ auto file = files_.Get(r.text_document.uri);
+ if (!file) {
+ return lsp::Null{};
+ }
+
+ auto def = (*file)->Definition(Conv(r.position));
+ if (!def) {
+ return lsp::Null{};
+ }
+
+ lsp::PrepareRenamePlaceholder out;
+ out.range = Conv(def->reference);
+ out.placeholder = def->text;
+ return lsp::PrepareRenameResult{out};
+}
+
+typename lsp::TextDocumentRenameRequest::ResultType //
+Server::Handle(const lsp::TextDocumentRenameRequest& r) {
+ auto file = files_.Get(r.text_document.uri);
+ if (!file) {
+ return lsp::Null{};
+ }
+
+ if (!(*file)->Definition(Conv(r.position))) {
+ return lsp::Null{};
+ }
+
+ std::vector<lsp::TextEdit> changes;
+ for (auto& ref : (*file)->References(Conv(r.position), /* include_declaration */ true)) {
+ lsp::TextEdit edit;
+ edit.range = Conv(ref);
+ edit.new_text = r.new_name;
+ changes.emplace_back(std::move(edit));
+ }
+
+ if (changes.empty()) {
+ return lsp::Null{};
+ }
+ std::unordered_map<lsp::DocumentUri, std::vector<lsp::TextEdit>> uri_changes;
+ uri_changes[r.text_document.uri] = std::move(changes);
+
+ lsp::WorkspaceEdit edit;
+ edit.changes = std::move(uri_changes);
+ return std::move(edit);
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/rename_test.cc b/src/tint/lang/wgsl/ls/rename_test.cc
new file mode 100644
index 0000000..8e16670
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/rename_test.cc
@@ -0,0 +1,240 @@
+// 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 <gtest/gtest.h>
+#include <algorithm>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/comparators.h"
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+#include "src/tint/utils/text/string.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ std::string_view markup;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+using LsRenameTest = LsTestWithParam<Case>;
+TEST_P(LsRenameTest, Rename) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.positions.size(), 1u);
+
+ auto uri = OpenDocument(parsed.clean);
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ // lsp::TextDocumentPrepareRenameRequest
+ {
+ lsp::TextDocumentPrepareRenameRequest req{};
+ req.text_document.uri = uri;
+ req.position = parsed.positions[0];
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.ranges.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ // Find the range that holds the position marker.
+ auto range =
+ std::find_if(parsed.ranges.begin(), parsed.ranges.end(),
+ [&](lsp::Range r) { return lsp::ContainsInclusive(r, req.position); });
+ ASSERT_NE(range, parsed.ranges.end());
+ ASSERT_EQ(range->start.line, range->end.line);
+ auto lines = Split(parsed.clean, "\n");
+ ASSERT_LT(range->start.line, lines.Length());
+ auto line = lines[range->start.line];
+
+ ASSERT_TRUE(res.Is<lsp::PrepareRenameResult>());
+ auto& rename_result = *res.Get<lsp::PrepareRenameResult>();
+ ASSERT_TRUE(rename_result.Is<lsp::PrepareRenamePlaceholder>());
+ auto& placeholder = *rename_result.Get<lsp::PrepareRenamePlaceholder>();
+
+ EXPECT_EQ(*range, placeholder.range);
+ auto expected_placeholder =
+ line.substr(range->start.character, range->end.character - range->start.character);
+ EXPECT_EQ(expected_placeholder, placeholder.placeholder);
+ }
+ }
+
+ // lsp::TextDocumentRenameRequest
+ {
+ lsp::TextDocumentRenameRequest req{};
+ req.text_document.uri = uri;
+ req.position = parsed.positions[0];
+ req.new_name = "RENAMED";
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.ranges.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<lsp::WorkspaceEdit>());
+ auto& edit = *res.Get<lsp::WorkspaceEdit>();
+ ASSERT_TRUE(edit.changes);
+ // There should only be one document in the list of changes, which must be the document
+ // we're renaming.
+ ASSERT_EQ(edit.changes->size(), 1u);
+ ASSERT_NE(edit.changes->find(uri), edit.changes->end());
+
+ auto& uri_changes = edit.changes->at(uri);
+ std::vector<lsp::Range> got_ranges;
+ for (auto& text_edit : uri_changes) {
+ EXPECT_EQ(text_edit.new_text, "RENAMED");
+ got_ranges.push_back(text_edit.range);
+ }
+ EXPECT_THAT(got_ranges, testing::UnorderedElementsAreArray(parsed.ranges));
+ }
+ }
+}
+
+// TODO(bclayton): Type aliases.
+INSTANTIATE_TEST_SUITE_P(,
+ LsRenameTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {R"(
+const「CONST」= 42;
+fn f() { _ =「⧘CONST」; }
+const C =「CONST」;
+)"}, // =========================================
+ {R"(
+var<private>「VAR」= 42;
+fn f() { _ =「V⧘AR」; }
+fn g() { _ = 「VAR」; }
+)"}, // =========================================
+ {R"(
+override「OVERRIDE」= 42;
+fn f() { _ =「OVERRID⧘E」+「OVERRIDE」; }
+)"}, // =========================================
+ {R"(
+struct「STRUCT」{ i : i32 }
+fn f(s :「⧘STRUCT」) { var v : 「STRUCT」; }
+)"}, // =========================================
+ {R"(
+struct S {「i」: i32 }
+fn f(s : S) { _ = s.「⧘i」; }
+fn g(s : S) { _ = s.「i」; }
+)"}, // =========================================
+ {R"(
+fn f(「p」: i32) { _ =「⧘p」* 「p」; }
+)"}, // =========================================
+ {R"(
+fn f() {
+ const「i」= 42;
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {R"(
+fn f() {
+ let「i」= 42;
+ _ =「⧘i」+「i」;
+}
+)"}, // =========================================
+ {R"(
+fn f() {
+ var「i」= 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {R"(
+fn f() {
+ var i = 42;
+ {
+ var「i」= 42;
+ 「i」=「⧘i」;
+ }
+}
+)"}, // =========================================
+ {R"(
+fn f() {
+ var「i」= 42;
+ {
+ var i = 42;
+ }
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {R"(
+const i = 42;
+fn f() {
+ var「i」= 42;
+ 「i」=「⧘i」;
+}
+)"}, // =========================================
+ {R"(
+const i = 42;
+fn f(「i」: i32) {
+ _ =「⧘i」*「i」;
+}
+)"}, // =========================================
+ {R"(
+fn「a」() {}
+fn b() { 「⧘a」(); }
+fn c() { 「a」(); }
+)"}, // =========================================
+ {R"(
+fn b() { 「a⧘」(); }
+fn「a」() {}
+fn c() { 「a」(); }
+)"}, // =========================================
+ {R"(
+fn f() {
+ let「i」= 42;
+ _ = (max(「i⧘」, 「i」) * 「i」);
+}
+)"}, // =========================================
+ {R"(
+const C = m⧘ax(1, 2);
+)"}, // =========================================
+ {R"(
+const C : i⧘32 = 42;
+)"},
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/sem_token.h b/src/tint/lang/wgsl/ls/sem_token.h
new file mode 100644
index 0000000..6a10ccc
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/sem_token.h
@@ -0,0 +1,52 @@
+// 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_SEM_TOKEN_H_
+#define SRC_TINT_LANG_WGSL_LS_SEM_TOKEN_H_
+
+#include <array>
+
+namespace tint::wgsl::ls {
+
+/// SemToken is a struct used to hold an enumerator of token types, and their corresponding names.
+struct SemToken {
+ enum Kind {
+ kEnum,
+ kEnumMember,
+ kFunction,
+ kMember,
+ kType,
+ kVariable,
+ };
+ static constexpr std::array kNames{
+ "enum", "enumMember", "function", "member", "type", "variable",
+ };
+};
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_SEM_TOKEN_H_
diff --git a/src/tint/lang/wgsl/ls/sem_tokens.cc b/src/tint/lang/wgsl/ls/sem_tokens.cc
new file mode 100644
index 0000000..3accd26
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/sem_tokens.cc
@@ -0,0 +1,141 @@
+// 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 "langsvr/lsp/comparators.h"
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "src/tint/lang/core/builtin_fn.h"
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/identifier_expression.h"
+#include "src/tint/lang/wgsl/ast/member_accessor_expression.h"
+#include "src/tint/lang/wgsl/ast/struct.h"
+#include "src/tint/lang/wgsl/ast/struct_member.h"
+#include "src/tint/lang/wgsl/ast/type.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
+#include "src/tint/lang/wgsl/ls/sem_token.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/function_expression.h"
+#include "src/tint/lang/wgsl/sem/type_expression.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+namespace {
+
+struct Token {
+ lsp::Position position;
+ size_t kind = 0;
+ size_t length = 0;
+};
+
+Token TokenFromRange(const tint::Source::Range& range, SemToken::Kind kind) {
+ Token tok;
+ tok.position = Conv(range.begin);
+ tok.length = range.end.column - range.begin.column;
+ tok.kind = kind;
+ return tok;
+}
+
+std::optional<SemToken::Kind> TokenKindFor(const sem::Expression* expr) {
+ return Switch<std::optional<SemToken::Kind>>(
+ Unwrap(expr), //
+ [](const sem::TypeExpression*) { return SemToken::kType; },
+ [](const sem::VariableUser*) { return SemToken::kVariable; },
+ [](const sem::FunctionExpression*) { return SemToken::kFunction; },
+ [](const sem::BuiltinEnumExpression<wgsl::BuiltinFn>*) { return SemToken::kFunction; },
+ [](const sem::BuiltinEnumExpressionBase*) { return SemToken::kEnumMember; },
+ [](tint::Default) { return std::nullopt; });
+}
+
+std::vector<Token> Tokens(File& file) {
+ std::vector<Token> tokens;
+ auto& sem = file.program.Sem();
+ for (auto* node : file.nodes) {
+ Switch(
+ node, //
+ [&](const ast::IdentifierExpression* expr) {
+ if (auto kind = TokenKindFor(sem.Get(expr))) {
+ tokens.push_back(TokenFromRange(expr->identifier->source.range, *kind));
+ }
+ },
+ [&](const ast::Struct* str) {
+ tokens.push_back(TokenFromRange(str->name->source.range, SemToken::kType));
+ },
+ [&](const ast::StructMember* member) {
+ tokens.push_back(TokenFromRange(member->name->source.range, SemToken::kMember));
+ },
+ [&](const ast::Variable* var) {
+ tokens.push_back(TokenFromRange(var->name->source.range, SemToken::kVariable));
+ },
+ [&](const ast::Function* fn) {
+ tokens.push_back(TokenFromRange(fn->name->source.range, SemToken::kFunction));
+ },
+ [&](const ast::MemberAccessorExpression* a) {
+ tokens.push_back(TokenFromRange(a->member->source.range, SemToken::kMember));
+ });
+ }
+ return tokens;
+}
+
+} // namespace
+
+typename lsp::TextDocumentSemanticTokensFullRequest::ResultType //
+Server::Handle(const lsp::TextDocumentSemanticTokensFullRequest& r) {
+ typename lsp::TextDocumentSemanticTokensFullRequest::SuccessType result;
+
+ if (auto file = files_.Get(r.text_document.uri)) {
+ lsp::SemanticTokens out;
+ // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens
+ Token last;
+
+ auto tokens = Tokens(**file);
+ std::sort(tokens.begin(), tokens.end(),
+ [](const Token& a, const Token& b) { return a.position < b.position; });
+
+ for (auto tok : tokens) {
+ if (last.position.line != tok.position.line) {
+ last.position.character = 0;
+ }
+ out.data.push_back(tok.position.line - last.position.line);
+ out.data.push_back(tok.position.character - last.position.character);
+ out.data.push_back(tok.length);
+ out.data.push_back(static_cast<langsvr::lsp::Uinteger>(tok.kind));
+ out.data.push_back(0); // modifiers
+ last = tok;
+ }
+
+ result = out;
+ }
+
+ return result;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/sem_tokens_test.cc b/src/tint/lang/wgsl/ls/sem_tokens_test.cc
new file mode 100644
index 0000000..d7fc9a0
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/sem_tokens_test.cc
@@ -0,0 +1,277 @@
+// 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 <gtest/gtest.h>
+#include <cstddef>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+#include "src/tint/lang/wgsl/ls/sem_token.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ std::string_view markup;
+ std::vector<SemToken::Kind> tokens;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+struct RangeAndToken {
+ lsp::Range range;
+ SemToken::Kind token;
+
+ bool operator==(const RangeAndToken& other) const {
+ return range == other.range && token == other.token;
+ }
+};
+
+std::ostream& operator<<(std::ostream& stream, const RangeAndToken& rt) {
+ return stream << "\n" << SemToken::kNames[rt.token] << ": " << rt.range;
+}
+
+using LsSemTokensTest = LsTestWithParam<Case>;
+TEST_P(LsSemTokensTest, SemTokens) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.positions.size(), 0u);
+ ASSERT_EQ(parsed.ranges.size(), GetParam().tokens.size());
+
+ lsp::TextDocumentSemanticTokensFullRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (parsed.ranges.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<lsp::SemanticTokens>());
+ std::vector<RangeAndToken> expect;
+ for (size_t i = 0; i < parsed.ranges.size(); i++) {
+ expect.push_back(RangeAndToken{parsed.ranges[i], GetParam().tokens[i]});
+ }
+ // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens
+ auto& data = res.Get<lsp::SemanticTokens>()->data;
+ ASSERT_EQ(data.size() % 5, 0u);
+ lsp::Position pos{};
+ std::vector<RangeAndToken> got;
+ for (size_t i = 0; i < data.size(); i += 5) {
+ const auto delta_line = data[i + 0];
+ const auto delta_start = data[i + 1];
+ const auto length = data[i + 2];
+ const auto token_type = data[i + 3];
+ const auto modifiers = data[i + 4];
+
+ pos.line += delta_line;
+ pos.character = (delta_line == 0) ? (pos.character + delta_start) : delta_start;
+ lsp::Range range;
+ range.start = pos;
+ range.end = lsp::Position{pos.line, pos.character + length};
+ auto token = static_cast<SemToken::Kind>(token_type);
+ ASSERT_EQ(modifiers, 0u);
+ got.push_back(RangeAndToken{range, token});
+ }
+ EXPECT_EQ(got, expect);
+ }
+}
+
+// TODO(bclayton): Type aliases.
+INSTANTIATE_TEST_SUITE_P(,
+ LsSemTokensTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ R"(
+const「CONST」= 42;
+fn 「f」() { _=「CONST」; }
+const 「C」=「CONST」;
+)",
+ {
+ /* 'CONST' */ SemToken::kVariable,
+ /* 'f' */ SemToken::kFunction,
+ /* 'CONST' */ SemToken::kVariable,
+ /* 'C' */ SemToken::kVariable,
+ /* 'CONST' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+var<「private」>「VAR」= 42;
+fn「f」() { _ =「VAR」; }
+fn「g」() { _ = 「VAR」; }
+)",
+ {
+ /* 'private' */ SemToken::kEnumMember,
+ /* 'VAR' */ SemToken::kVariable,
+ /* 'f' */ SemToken::kFunction,
+ /* 'VAR' */ SemToken::kVariable,
+ /* 'g' */ SemToken::kFunction,
+ /* 'VAR' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+override「OVERRIDE」= 42;
+fn「f」() { _ =「OVERRIDE」+「OVERRIDE」; }
+)",
+ {
+ /* 'OVERRIDE' */ SemToken::kVariable,
+ /* 'f' */ SemToken::kFunction,
+ /* 'OVERRIDE' */ SemToken::kVariable,
+ /* 'OVERRIDE' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+struct「STRUCT」{「i」:「i32」}
+fn「f」(「s」:「STRUCT」) { var「v」:「STRUCT」; }
+)",
+ {
+ /* 'STRUCT' */ SemToken::kType,
+ /* 'i' */ SemToken::kMember,
+ /* 'i32' */ SemToken::kType,
+ /* 'f' */ SemToken::kFunction,
+ /* 's' */ SemToken::kVariable,
+ /* 'STRUCT' */ SemToken::kType,
+ /* 'v' */ SemToken::kVariable,
+ /* 'STRUCT' */ SemToken::kType,
+ },
+ }, // =========================================
+ {
+ R"(
+struct「S」{「i」: 「i32」 }
+fn「f」(「s」 : 「S」) { _ = 「s」.「i」; }
+fn「g」(「s」 : 「S」) { _ = 「s」.「i」; }
+)",
+ {
+ /* 'S' */ SemToken::kType,
+ /* 'i' */ SemToken::kMember,
+ /* 'i32' */ SemToken::kType,
+ /* 'f' */ SemToken::kFunction,
+ /* 's' */ SemToken::kVariable,
+ /* 'S' */ SemToken::kType,
+ /* 's' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kMember,
+ /* 'g' */ SemToken::kFunction,
+ /* 's' */ SemToken::kVariable,
+ /* 'S' */ SemToken::kType,
+ /* 's' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kMember,
+ },
+ }, // =========================================
+ {
+ R"(
+fn「f」(「p」:「i32」) { _ =「p」*「p」; }
+)",
+ {
+ /* 'f' */ SemToken::kFunction,
+ /* 'p' */ SemToken::kVariable,
+ /* 'i32' */ SemToken::kType,
+ /* 'p' */ SemToken::kVariable,
+ /* 'p' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+fn「f」() {
+ const「i」= 42;
+ _ =「i」*「i」;
+}
+)",
+ {
+ /* 'f' */ SemToken::kFunction,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+fn「f」() {
+ let「i」= 42;
+ _ =「i」+「i」;
+}
+)",
+ {
+ /* 'f' */ SemToken::kFunction,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+fn「f」() {
+ var「i」= 42;
+ 「i」=「i」;
+}
+)",
+ {
+ /* 'f' */ SemToken::kFunction,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ },
+ }, // =========================================
+ {
+ R"(
+fn「f」() {
+ let「i」= 42;
+ _ = (「max」(「i」, 「i」) * 「i」);
+}
+)",
+ {
+ /* 'f' */ SemToken::kFunction,
+ /* 'i' */ SemToken::kVariable,
+ /* 'max' */ SemToken::kFunction,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ /* 'i' */ SemToken::kVariable,
+ },
+ },
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
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..6b526de
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/server.cc
@@ -0,0 +1,116 @@
+// 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"
+
+#include "src/tint/lang/wgsl/ls/sem_token.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+Server::Server(langsvr::Session& session) : session_(session) {
+ session.Register([&](const lsp::InitializeRequest&) {
+ lsp::InitializeResult result;
+ result.capabilities.definition_provider = true;
+ result.capabilities.document_symbol_provider = [] {
+ lsp::DocumentSymbolOptions opts;
+ return opts;
+ }();
+ result.capabilities.hover_provider = true;
+ result.capabilities.inlay_hint_provider = true;
+ result.capabilities.references_provider = [] {
+ lsp::ReferenceOptions opts;
+ return opts;
+ }();
+ result.capabilities.text_document_sync = [] {
+ lsp::TextDocumentSyncOptions opts;
+ opts.open_close = true;
+ opts.change = lsp::TextDocumentSyncKind::kIncremental;
+ return opts;
+ }();
+ result.capabilities.rename_provider = [] {
+ lsp::RenameOptions opts;
+ opts.prepare_provider = true;
+ return opts;
+ }();
+ result.capabilities.semantic_tokens_provider = [] {
+ lsp::SemanticTokensOptions opts;
+ opts.full = true;
+ for (auto name : SemToken::kNames) {
+ opts.legend.token_types.push_back(name);
+ }
+ return opts;
+ }();
+ result.capabilities.signature_help_provider = [] {
+ lsp::SignatureHelpOptions opts;
+ return opts;
+ }();
+ return result;
+ });
+
+ session.Register([&](const lsp::ShutdownRequest&) {
+ shutting_down_ = true;
+ return lsp::Null{};
+ });
+
+ // Notification handlers
+ session.Register([&](const lsp::CancelRequestNotification& n) { return Handle(n); });
+ session.Register([&](const lsp::InitializedNotification& n) { return Handle(n); });
+ session.Register([&](const lsp::SetTraceNotification& n) { return Handle(n); });
+ session.Register([&](const lsp::TextDocumentDidChangeNotification& n) { return Handle(n); });
+ session.Register([&](const lsp::TextDocumentDidCloseNotification& n) { return Handle(n); });
+ session.Register([&](const lsp::TextDocumentDidOpenNotification& n) { return Handle(n); });
+ session.Register(
+ [&](const lsp::WorkspaceDidChangeConfigurationNotification& n) { return Handle(n); });
+
+ // Request handlers
+ session.Register([&](const lsp::TextDocumentDefinitionRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentDocumentSymbolRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentHoverRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentInlayHintRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentPrepareRenameRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentReferencesRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentRenameRequest& r) { return Handle(r); });
+ session.Register(
+ [&](const lsp::TextDocumentSemanticTokensFullRequest& r) { return Handle(r); });
+ session.Register([&](const lsp::TextDocumentSignatureHelpRequest& r) { return Handle(r); });
+}
+
+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..e0df2f3
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/server.h
@@ -0,0 +1,165 @@
+// 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 <string>
+#include <utility>
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/session.h"
+
+#include "src/tint/lang/wgsl/ls/file.h"
+#include "src/tint/utils/containers/hashmap.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:
+ ////////////////////////////////////////////////////////////////////////////
+ // Requests
+ ////////////////////////////////////////////////////////////////////////////
+
+ /// Handler for langsvr::lsp::TextDocumentDefinitionRequest
+ typename langsvr::lsp::TextDocumentDefinitionRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentDefinitionRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentDocumentSymbolRequest
+ typename langsvr::lsp::TextDocumentDocumentSymbolRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentDocumentSymbolRequest& r);
+
+ /// Handler for langsvr::lsp::TextDocumentHoverRequest
+ typename langsvr::lsp::TextDocumentHoverRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentHoverRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentInlayHintRequest
+ typename langsvr::lsp::TextDocumentInlayHintRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentInlayHintRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentPrepareRenameRequest
+ typename langsvr::lsp::TextDocumentPrepareRenameRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentPrepareRenameRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentReferencesRequest
+ typename langsvr::lsp::TextDocumentReferencesRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentReferencesRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentRenameRequest
+ typename langsvr::lsp::TextDocumentRenameRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentRenameRequest&);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Notifications
+ ////////////////////////////////////////////////////////////////////////////
+
+ /// Handler for langsvr::lsp::CancelRequestNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::CancelRequestNotification&);
+
+ /// Handler for langsvr::lsp::InitializedNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::InitializedNotification&);
+
+ /// Handler for langsvr::lsp::SetTraceNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::SetTraceNotification&);
+
+ /// Handler for langsvr::lsp::TextDocumentSignatureHelpRequest
+ typename langsvr::lsp::TextDocumentSignatureHelpRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentSignatureHelpRequest&);
+
+ /// Handler for langsvr::lsp::TextDocumentDidOpenNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::TextDocumentDidOpenNotification&);
+
+ /// Handler for langsvr::lsp::TextDocumentDidCloseNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::TextDocumentDidCloseNotification&);
+
+ /// Handler for langsvr::lsp::TextDocumentDidChangeNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::TextDocumentDidChangeNotification&);
+
+ /// Handler for langsvr::lsp::TextDocumentSemanticTokensFullRequest
+ typename langsvr::lsp::TextDocumentSemanticTokensFullRequest::ResultType //
+ Handle(const langsvr::lsp::TextDocumentSemanticTokensFullRequest&);
+
+ /// Handler for langsvr::lsp::WorkspaceDidChangeConfigurationNotification
+ langsvr::Result<langsvr::SuccessType> //
+ Handle(const langsvr::lsp::WorkspaceDidChangeConfigurationNotification&);
+
+ /// Publishes the tint::Program diagnostics to the server via a
+ /// TextDocumentPublishDiagnosticsNotification.
+ langsvr::Result<langsvr::SuccessType> //
+ PublishDiagnostics(File& file);
+
+ /// 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 << std::forward<T>(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_;
+ /// Map of URI to File.
+ Hashmap<std::string, std::shared_ptr<File>, 8> files_;
+ /// 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_
diff --git a/src/tint/lang/wgsl/ls/set_trace.cc b/src/tint/lang/wgsl/ls/set_trace.cc
new file mode 100644
index 0000000..477b3d7
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/set_trace.cc
@@ -0,0 +1,39 @@
+// 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 "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+langsvr::Result<langsvr::SuccessType> Server::Handle(const lsp::SetTraceNotification&) {
+ return langsvr::Success;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/signature_help.cc b/src/tint/lang/wgsl/ls/signature_help.cc
new file mode 100644
index 0000000..401e621
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/signature_help.cc
@@ -0,0 +1,213 @@
+// 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 "src/tint/lang/core/intrinsic/table.h"
+#include "src/tint/lang/wgsl/intrinsic/dialect.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/lang/wgsl/sem/call.h"
+#include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace lsp = langsvr::lsp;
+
+namespace tint::wgsl::ls {
+
+namespace {
+
+std::vector<lsp::ParameterInformation> Params(const core::intrinsic::TableData& data,
+ const core::intrinsic::OverloadInfo& overload) {
+ std::vector<lsp::ParameterInformation> params;
+ for (size_t i = 0; i < overload.num_parameters; i++) {
+ lsp::ParameterInformation param_out;
+ auto& param_in = data[overload.parameters + i];
+ if (param_in.usage != core::ParameterUsage::kNone) {
+ param_out.label = std::string(core::ToString(param_in.usage));
+ } else {
+ param_out.label = "param-" + std::to_string(i);
+ }
+ params.push_back(std::move(param_out));
+ }
+ return params;
+}
+
+size_t CalcParamIndex(const Source& call_source, const Source::Location& carat) {
+ size_t index = 0;
+ int depth = 0;
+
+ auto start = call_source.range.begin;
+ auto end = std::min(call_source.range.end, carat);
+ auto& lines = call_source.file->content.lines;
+
+ for (auto line = start.line; line <= end.line; line++) {
+ auto start_column = line == start.line ? start.column : 0;
+ auto end_column = line == end.line ? end.column : 0;
+ auto text = lines[line - 1].substr(start_column - 1, end_column - start_column);
+ for (char c : text) {
+ switch (c) {
+ case '(':
+ case '[':
+ depth++;
+ break;
+ case ')':
+ case ']':
+ depth--;
+ break;
+ case ',':
+ if (depth == 1) {
+ index++;
+ }
+ }
+ }
+ }
+ return index;
+}
+
+void PrintOverload(StyledText& ss,
+ core::intrinsic::Context& context,
+ const core::intrinsic::OverloadInfo& overload,
+ std::string_view intrinsic_name) {
+ // Restore old style before returning.
+ auto prev_style = ss.Style();
+ TINT_DEFER(ss << prev_style);
+
+ core::intrinsic::TemplateState templates;
+
+ auto earliest_eval_stage = core::EvaluationStage::kConstant;
+
+ ss << style::Code << style::Function(intrinsic_name);
+
+ if (overload.num_explicit_templates > 0) {
+ ss << "<";
+ for (size_t i = 0; i < overload.num_explicit_templates; i++) {
+ const auto& tmpl = context.data[overload.templates + i];
+ if (i > 0) {
+ ss << ", ";
+ }
+ ss << style::Type(tmpl.name) << " ";
+ }
+ ss << ">";
+ }
+
+ ss << "(";
+ for (size_t i = 0; i < overload.num_parameters; i++) {
+ const auto& parameter = context.data[overload.parameters + i];
+ auto* matcher_indices = context.data[parameter.matcher_indices];
+
+ if (i > 0) {
+ ss << ", ";
+ }
+
+ if (parameter.usage != core::ParameterUsage::kNone) {
+ ss << style::Variable(parameter.usage, ": ");
+ }
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
+ }
+ ss << ")";
+ if (overload.return_matcher_indices.IsValid()) {
+ ss << " -> ";
+ auto* matcher_indices = context.data[overload.return_matcher_indices];
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
+ }
+
+ bool first = true;
+ auto separator = [&] {
+ ss << style::Plain(first ? " where:\n " : "\n ");
+ first = false;
+ };
+
+ for (size_t i = 0; i < overload.num_templates; i++) {
+ auto& tmpl = context.data[overload.templates + i];
+ if (auto* matcher_indices = context.data[tmpl.matcher_indices]) {
+ separator();
+
+ ss << style::Type(tmpl.name) << style::Plain(" is ");
+ if (tmpl.kind == core::intrinsic::TemplateInfo::Kind::kType) {
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
+ .PrintType(ss);
+ } else {
+ context.Match(templates, overload, matcher_indices, earliest_eval_stage)
+ .PrintNum(ss);
+ }
+ }
+ }
+}
+
+} // namespace
+
+typename lsp::TextDocumentSignatureHelpRequest::ResultType //
+Server::Handle(const lsp::TextDocumentSignatureHelpRequest& r) {
+ auto file = files_.Get(r.text_document.uri);
+ if (!file) {
+ return lsp::Null{};
+ }
+
+ auto& program = (*file)->program;
+ auto pos = Conv(r.position);
+
+ auto call = (*file)->NodeAt<sem::Call>(pos);
+ if (!call) {
+ return lsp::Null{};
+ }
+
+ lsp::SignatureHelp help;
+ help.active_parameter = CalcParamIndex(call->Declaration()->source, pos);
+ Switch(call->Target(), //
+ [&](const sem::BuiltinFn* target) {
+ auto& data = wgsl::intrinsic::Dialect::kData;
+ auto& builtins = data.builtins;
+ auto& intrinsic_info = builtins[static_cast<size_t>(target->Fn())];
+ std::string name{wgsl::str(target->Fn())};
+
+ for (size_t i = 0; i < intrinsic_info.num_overloads; i++) {
+ auto& overload = data[intrinsic_info.overloads + i];
+
+ auto params = Params(data, overload);
+
+ auto type_mgr = core::type::Manager::Wrap(program.Types());
+ auto symbols = SymbolTable::Wrap(program.Symbols());
+
+ StyledText ss;
+ core::intrinsic::Context ctx{data, type_mgr, symbols};
+ PrintOverload(ss, ctx, overload, name);
+
+ lsp::SignatureInformation sig;
+ sig.parameters = params;
+ sig.label = ss.Plain();
+ help.signatures.push_back(sig);
+
+ if (&overload == &target->Overload()) {
+ help.active_signature = i;
+ }
+ }
+ });
+
+ return help;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/signature_help_test.cc b/src/tint/lang/wgsl/ls/signature_help_test.cc
new file mode 100644
index 0000000..ceaf52a
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/signature_help_test.cc
@@ -0,0 +1,281 @@
+// 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 <gtest/gtest.h>
+#include <sstream>
+#include <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+std::vector<lsp::SignatureInformation> MaxSignatures() {
+ std::vector<lsp::SignatureInformation> out;
+
+ {
+ std::vector<lsp::ParameterInformation> parameters;
+ parameters.push_back(lsp::ParameterInformation{
+ /* label */ lsp::String("param-0"),
+ /* documentation */ {},
+ });
+ parameters.push_back(lsp::ParameterInformation{
+ /* label */ lsp::String("param-1"),
+ /* documentation */ {},
+ });
+
+ lsp::SignatureInformation sig{};
+ sig.label = R"('max(T, T) -> T' where:
+ 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16')";
+ sig.parameters = std::move(parameters);
+
+ out.push_back(std::move(sig));
+ }
+
+ {
+ std::vector<lsp::ParameterInformation> parameters;
+ parameters.push_back(lsp::ParameterInformation{
+ /* label */ lsp::String("param-0"),
+ /* documentation */ {},
+ });
+ parameters.push_back(lsp::ParameterInformation{
+ /* label */ lsp::String("param-1"),
+ /* documentation */ {},
+ });
+
+ lsp::SignatureInformation sig{};
+ sig.label = R"('max(vecN<T>, vecN<T>) -> vecN<T>' where:
+ 'T' is 'abstract-float', 'abstract-int', 'f32', 'i32', 'u32' or 'f16')";
+ sig.parameters = std::move(parameters);
+
+ out.push_back(std::move(sig));
+ }
+
+ return out;
+}
+
+struct Case {
+ std::string_view markup;
+ std::vector<lsp::SignatureInformation> signatures;
+ lsp::Uinteger active_signature = 0;
+ lsp::Uinteger active_parameter = 0;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.markup << "'";
+}
+
+using LsSignatureHelpTest = LsTestWithParam<Case>;
+TEST_P(LsSignatureHelpTest, SignatureHelp) {
+ auto parsed = ParseMarkers(GetParam().markup);
+ ASSERT_EQ(parsed.ranges.size(), 0u);
+ ASSERT_EQ(parsed.positions.size(), 1u);
+
+ lsp::TextDocumentSignatureHelpRequest req{};
+ req.text_document.uri = OpenDocument(parsed.clean);
+ req.position = parsed.positions[0];
+
+ for (auto& n : diagnostics_) {
+ for (auto& d : n.diagnostics) {
+ if (d.severity == lsp::DiagnosticSeverity::kError) {
+ FAIL() << "Error: " << d.message << "\nWGSL:\n" << parsed.clean;
+ }
+ }
+ }
+
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (GetParam().signatures.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<lsp::SignatureHelp>());
+ auto& got = *res.Get<lsp::SignatureHelp>();
+ EXPECT_EQ(got.signatures, GetParam().signatures);
+ EXPECT_EQ(got.active_signature, GetParam().active_signature);
+ EXPECT_EQ(got.active_parameter, GetParam().active_parameter);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ LsSignatureHelpTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ R"(
+const C = max(⧘1, 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C : i32 = max(⧘1, 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(⧘1, 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(1⧘, 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(1,⧘ 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max(1, 2⧘);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max(⧘ vec2(1), vec2(2));
+)",
+ MaxSignatures(),
+ /* active_signature */ 1,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(⧘ vec3(1), vec3(2));
+)",
+ MaxSignatures(),
+ /* active_signature */ 1,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(vec4(1) ⧘, vec4(2));
+)",
+ MaxSignatures(),
+ /* active_signature */ 1,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(vec2(1),⧘ vec2(2));
+)",
+ MaxSignatures(),
+ /* active_signature */ 1,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max(vec3(1), vec3(2) ⧘);
+)",
+ MaxSignatures(),
+ /* active_signature */ 1,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = min(max(1, ⧘2), max(3, 4));
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+fn f() {
+ let x = max(1, ⧘2);
+}
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max( (1 + (2⧘) * 3), 4);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(1, (2 + (3⧘) * 4));
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max( array(1,2,3)[1⧘], 2);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 0,
+ }, // =========================================
+ {
+ R"(
+const C = max(1, array(1,2,3)[⧘2]);
+)",
+ MaxSignatures(),
+ /* active_signature */ 0,
+ /* active_parameter */ 1,
+ }, // =========================================
+ {
+ R"(
+const C = max(1, 2) ⧘;
+)",
+ {},
+ },
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/symbols.cc b/src/tint/lang/wgsl/ls/symbols.cc
new file mode 100644
index 0000000..78771ba
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/symbols.cc
@@ -0,0 +1,95 @@
+// 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/ast/const.h"
+#include "src/tint/lang/wgsl/ls/server.h"
+
+#include "src/tint/lang/wgsl/ast/alias.h"
+#include "src/tint/lang/wgsl/ast/identifier.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/ast/struct.h"
+#include "src/tint/lang/wgsl/ls/utils.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::wgsl::ls {
+
+namespace lsp = langsvr::lsp;
+
+typename lsp::TextDocumentDocumentSymbolRequest::ResultType //
+Server::Handle(const lsp::TextDocumentDocumentSymbolRequest& r) {
+ typename lsp::TextDocumentDocumentSymbolRequest::SuccessType result = lsp::Null{};
+
+ std::vector<lsp::DocumentSymbol> symbols;
+ if (auto file = files_.Get(r.text_document.uri)) {
+ for (auto* decl : (*file)->program.AST().Functions()) {
+ lsp::DocumentSymbol sym;
+ sym.range = Conv(decl->source.range);
+ sym.selection_range = Conv(decl->name->source.range);
+ sym.kind = lsp::SymbolKind::kFunction;
+ sym.name = decl->name->symbol.NameView();
+ symbols.push_back(sym);
+ }
+ for (auto* decl : (*file)->program.AST().GlobalVariables()) {
+ lsp::DocumentSymbol sym;
+ sym.range = Conv(decl->source.range);
+ sym.selection_range = Conv(decl->name->source.range);
+ sym.kind =
+ decl->Is<ast::Const>() ? lsp::SymbolKind::kConstant : lsp::SymbolKind::kVariable;
+ sym.name = decl->name->symbol.NameView();
+ symbols.push_back(sym);
+ }
+ for (auto* decl : (*file)->program.AST().TypeDecls()) {
+ Switch(
+ decl, //
+ [&](const ast::Struct* str) {
+ lsp::DocumentSymbol sym;
+ sym.range = Conv(str->source.range);
+ sym.selection_range = Conv(decl->name->source.range);
+ sym.kind = lsp::SymbolKind::kStruct;
+ sym.name = decl->name->symbol.NameView();
+ symbols.push_back(sym);
+ },
+ [&](const ast::Alias* str) {
+ lsp::DocumentSymbol sym;
+ sym.range = Conv(str->source.range);
+ sym.selection_range = Conv(decl->name->source.range);
+ // TODO(bclayton): Is there a better symbol kind?
+ sym.kind = lsp::SymbolKind::kObject;
+ sym.name = decl->name->symbol.NameView();
+ symbols.push_back(sym);
+ });
+ }
+ }
+
+ if (!symbols.empty()) {
+ result = std::move(symbols);
+ }
+
+ return result;
+}
+
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/symbols_test.cc b/src/tint/lang/wgsl/ls/symbols_test.cc
new file mode 100644
index 0000000..33820c9
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/symbols_test.cc
@@ -0,0 +1,161 @@
+// 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 <string_view>
+
+#include "gmock/gmock.h"
+
+#include "langsvr/lsp/lsp.h"
+#include "langsvr/lsp/primitives.h"
+#include "langsvr/lsp/printer.h"
+#include "src/tint/lang/wgsl/ls/helpers_test.h"
+
+namespace tint::wgsl::ls {
+namespace {
+
+namespace lsp = langsvr::lsp;
+
+struct Case {
+ const std::string_view wgsl;
+ const std::vector<lsp::DocumentSymbol> symbols;
+};
+
+std::ostream& operator<<(std::ostream& stream, const Case& c) {
+ return stream << "wgsl: '" << c.wgsl << "'";
+}
+
+struct Symbol : lsp::DocumentSymbol {
+ explicit Symbol(std::string_view n) { name = n; }
+
+ Symbol& Kind(lsp::SymbolKind k) {
+ kind = k;
+ return *this;
+ }
+
+ Symbol& Range(lsp::Uinteger start_line,
+ lsp::Uinteger start_column,
+ lsp::Uinteger end_line,
+ lsp::Uinteger end_column) {
+ range = lsp::Range{{start_line, start_column}, {end_line, end_column}};
+ return *this;
+ }
+
+ Symbol& SelectionRange(lsp::Uinteger start_line,
+ lsp::Uinteger start_column,
+ lsp::Uinteger end_line,
+ lsp::Uinteger end_column) {
+ selection_range = lsp::Range{{start_line, start_column}, {end_line, end_column}};
+ return *this;
+ }
+};
+
+using LsSymbolsTest = LsTestWithParam<Case>;
+TEST_P(LsSymbolsTest, Symbols) {
+ lsp::TextDocumentDocumentSymbolRequest req{};
+ req.text_document.uri = OpenDocument(GetParam().wgsl);
+ auto future = client_session_.Send(req);
+ ASSERT_EQ(future, langsvr::Success);
+ auto res = future->get();
+ if (GetParam().symbols.empty()) {
+ ASSERT_TRUE(res.Is<lsp::Null>());
+ } else {
+ ASSERT_TRUE(res.Is<std::vector<lsp::DocumentSymbol>>());
+ EXPECT_THAT(*res.Get<std::vector<lsp::DocumentSymbol>>(),
+ testing::ContainerEq(GetParam().symbols));
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ LsSymbolsTest,
+ ::testing::ValuesIn(std::vector<Case>{
+ {
+ "",
+ {},
+ },
+ {
+ ""
+ /* 0 */ "const C = 1;\n"
+ /* 1 */ "/* blah */ var V : i32 = 2i;\n"
+ /* 2 */ "override O = 3f;\n",
+ {
+ Symbol{"C"}
+ .Kind(lsp::SymbolKind::kConstant)
+ .Range(0, 0, 0, 11)
+ .SelectionRange(0, 6, 0, 7),
+ Symbol{"V"}
+ .Kind(lsp::SymbolKind::kVariable)
+ .Range(1, 11, 1, 27)
+ .SelectionRange(1, 15, 1, 16),
+ Symbol{"O"}
+ .Kind(lsp::SymbolKind::kVariable)
+ .Range(2, 0, 2, 15)
+ .SelectionRange(2, 9, 2, 10),
+ },
+ },
+ {
+ ""
+ /* 0 */ "fn fa() {}\n"
+ /* 1 */ "/* blah */ fn fb() -> i32 {\n"
+ /* 2 */ " return 1;\n"
+ /* 3 */ "} // blah",
+ {
+ Symbol{"fa"}
+ .Kind(lsp::SymbolKind::kFunction)
+ .Range(0, 0, 0, 10)
+ .SelectionRange(0, 3, 0, 5),
+ Symbol{"fb"}
+ .Kind(lsp::SymbolKind::kFunction)
+ .Range(1, 11, 3, 1)
+ .SelectionRange(1, 14, 1, 16),
+ },
+ },
+ {
+ ""
+ /* 0 */ "struct s1 { i : i32 }\n"
+ /* 1 */ "alias A = i32;\n"
+ /* 2 */ "/* blah */ struct s2 {\n"
+ /* 3 */ " a : i32,\n"
+ /* 4 */ "} // blah",
+ {
+ Symbol{"s1"}
+ .Kind(lsp::SymbolKind::kStruct)
+ .Range(0, 0, 0, 21)
+ .SelectionRange(0, 7, 0, 9),
+ Symbol{"A"}
+ .Kind(lsp::SymbolKind::kObject)
+ .Range(1, 0, 1, 13)
+ .SelectionRange(1, 6, 1, 7),
+ Symbol{"s2"}
+ .Kind(lsp::SymbolKind::kStruct)
+ .Range(2, 11, 4, 1)
+ .SelectionRange(2, 18, 2, 20),
+ },
+ },
+ }));
+
+} // namespace
+} // namespace tint::wgsl::ls
diff --git a/src/tint/lang/wgsl/ls/utils.h b/src/tint/lang/wgsl/ls/utils.h
new file mode 100644
index 0000000..921fbc1
--- /dev/null
+++ b/src/tint/lang/wgsl/ls/utils.h
@@ -0,0 +1,79 @@
+// 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_UTILS_H_
+#define SRC_TINT_LANG_WGSL_LS_UTILS_H_
+
+#include "langsvr/lsp/lsp.h"
+#include "src/tint/lang/wgsl/sem/value_expression.h"
+#include "src/tint/utils/diagnostic/source.h"
+#include "src/tint/utils/rtti/castable.h"
+
+// Forward declarations
+namespace tint::sem {
+class Node;
+}
+
+namespace tint::wgsl::ls {
+
+/// @return the langsvr::lsp::Position @p pos converted to a tint::Source::Location
+inline Source::Location Conv(langsvr::lsp::Position pos) {
+ Source::Location loc;
+ loc.line = static_cast<uint32_t>(pos.line + 1);
+ loc.column = static_cast<uint32_t>(pos.character + 1);
+ return loc;
+}
+
+/// @return the tint::Source::Location @p loc converted to a langsvr::lsp::Position
+inline langsvr::lsp::Position Conv(Source::Location loc) {
+ langsvr::lsp::Position pos;
+ pos.line = loc.line - 1;
+ pos.character = loc.column - 1;
+ return pos;
+}
+
+/// @return the tint::Source::Range @p rng converted to a langsvr::lsp::Range
+inline langsvr::lsp::Range Conv(Source::Range rng) {
+ langsvr::lsp::Range out;
+ out.start = Conv(rng.begin);
+ out.end = Conv(rng.end);
+ return out;
+}
+
+/// @returns the sem::Load() and sem::Materialize() unwrapped sem::ValueExpression, if `T` is a
+/// sem::ValueExpression, otherwise returns @p node.
+template <typename T>
+const T* Unwrap(const T* node) {
+ if (auto* expr = As<sem::ValueExpression, CastFlags::kDontErrorOnImpossibleCast>(node)) {
+ return As<T>(expr->Unwrap());
+ }
+ return node;
+}
+
+} // namespace tint::wgsl::ls
+
+#endif // SRC_TINT_LANG_WGSL_LS_UTILS_H_
diff --git a/src/tint/lang/wgsl/reader/parser/global_constant_decl_test.cc b/src/tint/lang/wgsl/reader/parser/global_constant_decl_test.cc
index c80de54..904da07 100644
--- a/src/tint/lang/wgsl/reader/parser/global_constant_decl_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/global_constant_decl_test.cc
@@ -61,9 +61,14 @@
ast::CheckIdentifier(c->type, "f32");
EXPECT_EQ(c->source.range.begin.line, 1u);
- EXPECT_EQ(c->source.range.begin.column, 7u);
+ EXPECT_EQ(c->source.range.begin.column, 1u);
EXPECT_EQ(c->source.range.end.line, 1u);
- EXPECT_EQ(c->source.range.end.column, 8u);
+ EXPECT_EQ(c->source.range.end.column, 19u);
+
+ EXPECT_EQ(c->name->source.range.begin.line, 1u);
+ EXPECT_EQ(c->name->source.range.begin.column, 7u);
+ EXPECT_EQ(c->name->source.range.end.line, 1u);
+ EXPECT_EQ(c->name->source.range.end.column, 8u);
ASSERT_NE(c->initializer, nullptr);
EXPECT_TRUE(c->initializer->Is<ast::LiteralExpression>());
@@ -85,9 +90,14 @@
EXPECT_EQ(c->type, nullptr);
EXPECT_EQ(c->source.range.begin.line, 1u);
- EXPECT_EQ(c->source.range.begin.column, 7u);
+ EXPECT_EQ(c->source.range.begin.column, 1u);
EXPECT_EQ(c->source.range.end.line, 1u);
- EXPECT_EQ(c->source.range.end.column, 8u);
+ EXPECT_EQ(c->source.range.end.column, 13u);
+
+ EXPECT_EQ(c->name->source.range.begin.line, 1u);
+ EXPECT_EQ(c->name->source.range.begin.column, 7u);
+ EXPECT_EQ(c->name->source.range.end.line, 1u);
+ EXPECT_EQ(c->name->source.range.end.column, 8u);
ASSERT_NE(c->initializer, nullptr);
EXPECT_TRUE(c->initializer->Is<ast::LiteralExpression>());
@@ -137,9 +147,14 @@
ast::CheckIdentifier(override->type, "f32");
EXPECT_EQ(override->source.range.begin.line, 1u);
- EXPECT_EQ(override->source.range.begin.column, 17u);
+ EXPECT_EQ(override->source.range.begin.column, 8u);
EXPECT_EQ(override->source.range.end.line, 1u);
- EXPECT_EQ(override->source.range.end.column, 18u);
+ EXPECT_EQ(override->source.range.end.column, 29u);
+
+ EXPECT_EQ(override->name->source.range.begin.line, 1u);
+ EXPECT_EQ(override->name->source.range.begin.column, 17u);
+ EXPECT_EQ(override->name->source.range.end.line, 1u);
+ EXPECT_EQ(override->name->source.range.end.column, 18u);
ASSERT_NE(override->initializer, nullptr);
EXPECT_TRUE(override->initializer->Is<ast::LiteralExpression>());
@@ -167,9 +182,14 @@
ast::CheckIdentifier(override->type, "f32");
EXPECT_EQ(override->source.range.begin.line, 1u);
- EXPECT_EQ(override->source.range.begin.column, 18u);
+ EXPECT_EQ(override->source.range.begin.column, 9u);
EXPECT_EQ(override->source.range.end.line, 1u);
- EXPECT_EQ(override->source.range.end.column, 19u);
+ EXPECT_EQ(override->source.range.end.column, 30u);
+
+ EXPECT_EQ(override->name->source.range.begin.line, 1u);
+ EXPECT_EQ(override->name->source.range.begin.column, 18u);
+ EXPECT_EQ(override->name->source.range.end.line, 1u);
+ EXPECT_EQ(override->name->source.range.end.column, 19u);
ASSERT_NE(override->initializer, nullptr);
EXPECT_TRUE(override->initializer->Is<ast::LiteralExpression>());
@@ -197,9 +217,14 @@
ast::CheckIdentifier(override->type, "f32");
EXPECT_EQ(override->source.range.begin.line, 1u);
- EXPECT_EQ(override->source.range.begin.column, 10u);
+ EXPECT_EQ(override->source.range.begin.column, 1u);
EXPECT_EQ(override->source.range.end.line, 1u);
- EXPECT_EQ(override->source.range.end.column, 11u);
+ EXPECT_EQ(override->source.range.end.column, 22u);
+
+ EXPECT_EQ(override->name->source.range.begin.line, 1u);
+ EXPECT_EQ(override->name->source.range.begin.column, 10u);
+ EXPECT_EQ(override->name->source.range.end.line, 1u);
+ EXPECT_EQ(override->name->source.range.end.column, 11u);
ASSERT_NE(override->initializer, nullptr);
EXPECT_TRUE(override->initializer->Is<ast::LiteralExpression>());
diff --git a/src/tint/lang/wgsl/reader/parser/global_variable_decl_test.cc b/src/tint/lang/wgsl/reader/parser/global_variable_decl_test.cc
index 4105d12..d53b6f7 100644
--- a/src/tint/lang/wgsl/reader/parser/global_variable_decl_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/global_variable_decl_test.cc
@@ -48,9 +48,14 @@
ast::CheckIdentifier(var->declared_address_space, "private");
EXPECT_EQ(var->source.range.begin.line, 1u);
- EXPECT_EQ(var->source.range.begin.column, 14u);
+ EXPECT_EQ(var->source.range.begin.column, 1u);
EXPECT_EQ(var->source.range.end.line, 1u);
- EXPECT_EQ(var->source.range.end.column, 15u);
+ EXPECT_EQ(var->source.range.end.column, 21u);
+
+ EXPECT_EQ(var->name->source.range.begin.line, 1u);
+ EXPECT_EQ(var->name->source.range.begin.column, 14u);
+ EXPECT_EQ(var->name->source.range.end.line, 1u);
+ EXPECT_EQ(var->name->source.range.end.column, 15u);
ASSERT_EQ(var->initializer, nullptr);
}
@@ -72,9 +77,14 @@
ast::CheckIdentifier(var->declared_address_space, "private");
EXPECT_EQ(var->source.range.begin.line, 1u);
- EXPECT_EQ(var->source.range.begin.column, 14u);
+ EXPECT_EQ(var->source.range.begin.column, 1u);
EXPECT_EQ(var->source.range.end.line, 1u);
- EXPECT_EQ(var->source.range.end.column, 15u);
+ EXPECT_EQ(var->source.range.end.column, 26u);
+
+ EXPECT_EQ(var->name->source.range.begin.line, 1u);
+ EXPECT_EQ(var->name->source.range.begin.column, 14u);
+ EXPECT_EQ(var->name->source.range.end.line, 1u);
+ EXPECT_EQ(var->name->source.range.end.column, 15u);
ASSERT_NE(var->initializer, nullptr);
ASSERT_TRUE(var->initializer->Is<ast::FloatLiteralExpression>());
@@ -97,9 +107,14 @@
ast::CheckIdentifier(var->declared_address_space, "uniform");
EXPECT_EQ(var->source.range.begin.line, 1u);
- EXPECT_EQ(var->source.range.begin.column, 36u);
+ EXPECT_EQ(var->source.range.begin.column, 23u);
EXPECT_EQ(var->source.range.end.line, 1u);
- EXPECT_EQ(var->source.range.end.column, 37u);
+ EXPECT_EQ(var->source.range.end.column, 43u);
+
+ EXPECT_EQ(var->name->source.range.begin.line, 1u);
+ EXPECT_EQ(var->name->source.range.begin.column, 36u);
+ EXPECT_EQ(var->name->source.range.end.line, 1u);
+ EXPECT_EQ(var->name->source.range.end.column, 37u);
ASSERT_EQ(var->initializer, nullptr);
@@ -127,9 +142,14 @@
ast::CheckIdentifier(var->declared_address_space, "uniform");
EXPECT_EQ(var->source.range.begin.line, 1u);
- EXPECT_EQ(var->source.range.begin.column, 36u);
+ EXPECT_EQ(var->source.range.begin.column, 23u);
EXPECT_EQ(var->source.range.end.line, 1u);
- EXPECT_EQ(var->source.range.end.column, 37u);
+ EXPECT_EQ(var->source.range.end.column, 43u);
+
+ EXPECT_EQ(var->name->source.range.begin.line, 1u);
+ EXPECT_EQ(var->name->source.range.begin.column, 36u);
+ EXPECT_EQ(var->name->source.range.end.line, 1u);
+ EXPECT_EQ(var->name->source.range.end.column, 37u);
ASSERT_EQ(var->initializer, nullptr);
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index 315d701..d4ba3ca 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -28,6 +28,7 @@
#include "src/tint/lang/wgsl/reader/parser/parser.h"
#include <limits>
+#include <utility>
#include "src/tint/lang/core/attribute.h"
#include "src/tint/lang/core/type/depth_texture.h"
@@ -50,6 +51,7 @@
#include "src/tint/lang/wgsl/ast/stage_attribute.h"
#include "src/tint/lang/wgsl/ast/switch_statement.h"
#include "src/tint/lang/wgsl/ast/unary_op_expression.h"
+#include "src/tint/lang/wgsl/ast/var.h"
#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
#include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
#include "src/tint/lang/wgsl/reader/parser/classify_template_args.h"
@@ -666,6 +668,7 @@
// global_variable_decl
// : variable_attribute_list* variable_decl (EQUAL expression)?
Maybe<const ast::Variable*> Parser::global_variable_decl(AttributeList& attrs) {
+ MultiTokenSource decl_source(this);
auto decl = variable_decl();
if (decl.errored) {
return Failure::kErrored;
@@ -688,7 +691,7 @@
TINT_DEFER(attrs.Clear());
- return builder_.create<ast::Var>(decl->source, // source
+ return builder_.create<ast::Var>(decl_source(), // source
builder_.Ident(decl->name), // symbol
decl->type, // type
decl->address_space, // address space
@@ -705,6 +708,7 @@
Maybe<const ast::Variable*> Parser::global_constant_decl(AttributeList& attrs) {
bool is_overridable = false;
const char* use = nullptr;
+ MultiTokenSource decl_source(this);
Source source;
if (match(Token::Type::kConst)) {
use = "'const' declaration";
@@ -746,17 +750,17 @@
TINT_DEFER(attrs.Clear());
if (is_overridable) {
- return builder_.Override(decl->name->source, // source
- decl->name, // symbol
- decl->type, // type
- initializer, // initializer
- std::move(attrs)); // attributes
+ return builder_.Override(decl_source(), // source
+ decl->name, // symbol
+ decl->type, // type
+ initializer, // initializer
+ std::move(attrs)); // attributes
}
- return builder_.GlobalConst(decl->name->source, // source
- decl->name, // symbol
- decl->type, // type
- initializer, // initializer
- std::move(attrs)); // attributes
+ return builder_.GlobalConst(decl_source(), // source
+ decl->name, // symbol
+ decl->type, // type
+ initializer, // initializer
+ std::move(attrs)); // attributes
}
// variable_decl
@@ -974,7 +978,7 @@
// struct_decl
// : STRUCT IDENT struct_body_decl
Maybe<const ast::Struct*> Parser::struct_decl() {
- auto& t = peek();
+ MultiTokenSource source(this);
if (!match(Token::Type::kStruct)) {
return Failure::kNoMatch;
@@ -990,7 +994,7 @@
return Failure::kErrored;
}
- return builder_.Structure(t.source(), name.value, std::move(body.value));
+ return builder_.Structure(source(), name.value, std::move(body.value));
}
// struct_body_decl
diff --git a/src/tint/lang/wgsl/reader/parser/struct_decl_test.cc b/src/tint/lang/wgsl/reader/parser/struct_decl_test.cc
index 9733936..353e5fe 100644
--- a/src/tint/lang/wgsl/reader/parser/struct_decl_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/struct_decl_test.cc
@@ -46,6 +46,16 @@
ASSERT_EQ(s->members.Length(), 2u);
EXPECT_EQ(s->members[0]->name->symbol, p->builder().Symbols().Register("a"));
EXPECT_EQ(s->members[1]->name->symbol, p->builder().Symbols().Register("b"));
+
+ EXPECT_EQ(s->source.range.begin.line, 2u);
+ EXPECT_EQ(s->source.range.begin.column, 1u);
+ EXPECT_EQ(s->source.range.end.line, 5u);
+ EXPECT_EQ(s->source.range.end.column, 2u);
+
+ EXPECT_EQ(s->name->source.range.begin.line, 2u);
+ EXPECT_EQ(s->name->source.range.begin.column, 8u);
+ EXPECT_EQ(s->name->source.range.end.line, 2u);
+ EXPECT_EQ(s->name->source.range.end.column, 9u);
}
TEST_F(WGSLParserTest, StructDecl_Unicode_Parses) {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index f54aba6..b838c02 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -575,22 +575,31 @@
ControlStackScope scope(this, loop_inst);
+ auto& body_behaviors = program_.Sem().Get(stmt->body)->Behaviors();
{
TINT_SCOPED_ASSIGNMENT(current_block_, loop_inst->Body());
EmitStatements(stmt->body->statements);
- // The current block didn't `break`, `return` or `continue`, go to the continuing block.
+ // The current block didn't `break`, `return` or `continue`, go to the continuing block
+ // or mark the end of the block as unreachable.
if (NeedTerminator()) {
- SetTerminator(builder_.Continue(loop_inst));
+ if (body_behaviors.Contains(sem::Behavior::kNext)) {
+ SetTerminator(builder_.Continue(loop_inst));
+ } else {
+ SetTerminator(builder_.Unreachable());
+ }
}
}
- {
+ // Emit a continuing block if it is reachable.
+ if (body_behaviors.Contains(sem::Behavior::kNext) ||
+ body_behaviors.Contains(sem::Behavior::kContinue)) {
TINT_SCOPED_ASSIGNMENT(current_block_, loop_inst->Continuing());
if (stmt->continuing) {
EmitBlock(stmt->continuing);
}
+
// Branch back to the start block if the continue target didn't terminate already
if (NeedTerminator()) {
SetTerminator(builder_.NextIteration(loop_inst));
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
index 9867cb4..8ae7aa1 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
@@ -267,13 +267,10 @@
%b1 = block {
if true [t: %b2] { # if_1
%b2 = block { # true
- loop [b: %b3, c: %b4] { # loop_1
+ loop [b: %b3] { # loop_1
%b3 = block { # body
exit_loop # loop_1
}
- %b4 = block { # continuing
- next_iteration %b3
- }
}
exit_if # if_1
}
@@ -296,19 +293,16 @@
ASSERT_EQ(1u, m.functions.Length());
- EXPECT_EQ(1u, loop->Body()->InboundSiblingBranches().Length());
+ EXPECT_EQ(0u, loop->Body()->InboundSiblingBranches().Length());
EXPECT_EQ(0u, loop->Continuing()->InboundSiblingBranches().Length());
EXPECT_EQ(Disassemble(m),
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
- loop [b: %b2, c: %b3] { # loop_1
+ loop [b: %b2] { # loop_1
%b2 = block { # body
exit_loop # loop_1
}
- %b3 = block { # continuing
- next_iteration %b2
- }
}
ret
}
@@ -465,19 +459,16 @@
ASSERT_EQ(1u, m.functions.Length());
- EXPECT_EQ(1u, loop->Body()->InboundSiblingBranches().Length());
+ EXPECT_EQ(0u, loop->Body()->InboundSiblingBranches().Length());
EXPECT_EQ(0u, loop->Continuing()->InboundSiblingBranches().Length());
EXPECT_EQ(Disassemble(m),
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
- loop [b: %b2, c: %b3] { # loop_1
+ loop [b: %b2] { # loop_1
%b2 = block { # body
ret
}
- %b3 = block { # continuing
- next_iteration %b2
- }
}
unreachable
}
@@ -506,22 +497,19 @@
ASSERT_EQ(1u, m.functions.Length());
- EXPECT_EQ(1u, loop->Body()->InboundSiblingBranches().Length());
+ EXPECT_EQ(0u, loop->Body()->InboundSiblingBranches().Length());
EXPECT_EQ(0u, loop->Continuing()->InboundSiblingBranches().Length());
EXPECT_EQ(Disassemble(m),
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
- loop [b: %b2, c: %b3] { # loop_1
+ loop [b: %b2] { # loop_1
%b2 = block { # body
ret
}
- %b3 = block { # continuing
- break_if true %b2
- }
}
- if true [t: %b4] { # if_1
- %b4 = block { # true
+ if true [t: %b3] { # if_1
+ %b3 = block { # true
ret
}
}
@@ -544,26 +532,23 @@
ASSERT_EQ(1u, m.functions.Length());
- EXPECT_EQ(1u, loop->Body()->InboundSiblingBranches().Length());
- EXPECT_EQ(1u, loop->Continuing()->InboundSiblingBranches().Length());
+ EXPECT_EQ(0u, loop->Body()->InboundSiblingBranches().Length());
+ EXPECT_EQ(0u, loop->Continuing()->InboundSiblingBranches().Length());
EXPECT_EQ(Disassemble(m),
R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
%b1 = block {
- loop [b: %b2, c: %b3] { # loop_1
+ loop [b: %b2] { # loop_1
%b2 = block { # body
- if true [t: %b4, f: %b5] { # if_1
- %b4 = block { # true
+ if true [t: %b3, f: %b4] { # if_1
+ %b3 = block { # true
exit_loop # loop_1
}
- %b5 = block { # false
+ %b4 = block { # false
exit_loop # loop_1
}
}
- continue %b3
- }
- %b3 = block { # continuing
- next_iteration %b2
+ unreachable
}
}
ret
@@ -609,27 +594,24 @@
continue %b5
}
%b5 = block { # continuing
- loop [b: %b8, c: %b9] { # loop_3
+ loop [b: %b8] { # loop_3
%b8 = block { # body
exit_loop # loop_3
}
- %b9 = block { # continuing
- next_iteration %b8
- }
}
- loop [b: %b10, c: %b11] { # loop_4
- %b10 = block { # body
- continue %b11
+ loop [b: %b9, c: %b10] { # loop_4
+ %b9 = block { # body
+ continue %b10
}
- %b11 = block { # continuing
- break_if true %b10
+ %b10 = block { # continuing
+ break_if true %b9
}
}
next_iteration %b4
}
}
- if true [t: %b12] { # if_3
- %b12 = block { # true
+ if true [t: %b11] { # if_3
+ %b11 = block { # true
exit_loop # loop_1
}
}
diff --git a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
index a36e21f..0554f9a 100644
--- a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
@@ -106,7 +106,7 @@
case AttributeKind::kSize:
return o << "@size";
case AttributeKind::kStageCompute:
- return o << "@stage(compute)";
+ return o << "@compute";
case AttributeKind::kStride:
return o << "@stride";
case AttributeKind::kWorkgroupSize:
@@ -192,7 +192,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- "1:2 error: '@stage' is not valid for " + thing,
+ "1:2 error: '@compute' is not valid for " + thing,
},
TestParams{
{AttributeKind::kStride},
@@ -547,7 +547,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for function parameters)",
+ R"(1:2 error: '@compute' is not valid for function parameters)",
},
TestParams{
{AttributeKind::kStride},
@@ -632,7 +632,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for non-entry point function return types)",
+ R"(1:2 error: '@compute' is not valid for non-entry point function return types)",
},
TestParams{
{AttributeKind::kStride},
@@ -722,7 +722,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for function parameters)",
+ R"(1:2 error: '@compute' is not valid for function parameters)",
},
TestParams{
{AttributeKind::kStride},
@@ -823,7 +823,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for function parameters)",
+ R"(1:2 error: '@compute' is not valid for function parameters)",
},
TestParams{
{AttributeKind::kStride},
@@ -930,7 +930,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for function parameters)",
+ R"(1:2 error: '@compute' is not valid for function parameters)",
},
TestParams{
{AttributeKind::kStride},
@@ -1019,7 +1019,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for entry point return types)",
+ R"(1:2 error: '@compute' is not valid for entry point return types)",
},
TestParams{
{AttributeKind::kStride},
@@ -1117,7 +1117,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for entry point return types)",
+ R"(1:2 error: '@compute' is not valid for entry point return types)",
},
TestParams{
{AttributeKind::kStride},
@@ -1218,7 +1218,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for entry point return types)",
+ R"(1:2 error: '@compute' is not valid for entry point return types)",
},
TestParams{
{AttributeKind::kStride},
@@ -1342,7 +1342,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for 'struct' declarations)",
+ R"(1:2 error: '@compute' is not valid for 'struct' declarations)",
},
TestParams{
{AttributeKind::kStride},
@@ -1434,7 +1434,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for 'struct' members)",
+ R"(1:2 error: '@compute' is not valid for 'struct' members)",
},
TestParams{
{AttributeKind::kStride},
@@ -1694,7 +1694,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for 'array' types)",
+ R"(1:2 error: '@compute' is not valid for 'array' types)",
},
TestParams{
{AttributeKind::kStride},
@@ -1785,7 +1785,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for module-scope 'var')",
+ R"(1:2 error: '@compute' is not valid for module-scope 'var')",
},
TestParams{
{AttributeKind::kStride},
@@ -1889,7 +1889,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for 'const' declaration)",
+ R"(1:2 error: '@compute' is not valid for 'const' declaration)",
},
TestParams{
{AttributeKind::kStride},
@@ -1970,7 +1970,7 @@
},
TestParams{
{AttributeKind::kStageCompute},
- R"(1:2 error: '@stage' is not valid for 'override' declaration)",
+ R"(1:2 error: '@compute' is not valid for 'override' declaration)",
},
TestParams{
{AttributeKind::kStride},
diff --git a/src/tint/lang/wgsl/resolver/function_validation_test.cc b/src/tint/lang/wgsl/resolver/function_validation_test.cc
index 3de0b09..764af82 100644
--- a/src/tint/lang/wgsl/resolver/function_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/function_validation_test.cc
@@ -456,7 +456,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(56:78 error: duplicate stage attribute
+ R"(56:78 error: duplicate fragment attribute
12:34 note: first attribute declared here)");
}
diff --git a/src/tint/lang/wgsl/resolver/side_effects_test.cc b/src/tint/lang/wgsl/resolver/side_effects_test.cc
index b9fa38b..7d8bd2c 100644
--- a/src/tint/lang/wgsl/resolver/side_effects_test.cc
+++ b/src/tint/lang/wgsl/resolver/side_effects_test.cc
@@ -108,7 +108,7 @@
TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
GlobalVar("a", ty.f32(), core::AddressSpace::kPrivate);
- auto* expr = Call("dpdx", "a");
+ auto* expr = Call("sqrt", "a");
Func("f", tint::Empty, ty.void_(), Vector{Ignore(expr)},
Vector{create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
@@ -334,30 +334,30 @@
C("textureSampleCompareLevel",
Vector{"tdepth2d", "scomp", "vf2", "f"},
false,
- true), //
- C("textureSampleGrad", Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false, true), //
- C("textureSampleLevel", Vector{"t2d", "s2d", "vf2", "f"}, false, true), //
- C("transpose", Vector{"m"}, false, true), //
- C("trunc", Vector{"f"}, false, true), //
- C("unpack2x16float", Vector{"u"}, false, true), //
- C("unpack2x16snorm", Vector{"u"}, false, true), //
- C("unpack2x16unorm", Vector{"u"}, false, true), //
- C("unpack4x8snorm", Vector{"u"}, false, true), //
- C("unpack4x8unorm", Vector{"u"}, false, true), //
- C("storageBarrier", tint::Empty, false, false, ast::PipelineStage::kCompute), //
- C("workgroupBarrier", tint::Empty, false, false, ast::PipelineStage::kCompute), //
- C("textureSample", Vector{"t2d", "s2d", "vf2"}, false, true), //
- C("textureSampleBias", Vector{"t2d", "s2d", "vf2", "f"}, false, true), //
- C("textureSampleCompare", Vector{"tdepth2d", "scomp", "vf2", "f"}, false, true), //
- C("dpdx", Vector{"f"}, false, true), //
- C("dpdxCoarse", Vector{"f"}, false, true), //
- C("dpdxFine", Vector{"f"}, false, true), //
- C("dpdy", Vector{"f"}, false, true), //
- C("dpdyCoarse", Vector{"f"}, false, true), //
- C("dpdyFine", Vector{"f"}, false, true), //
- C("fwidth", Vector{"f"}, false, true), //
- C("fwidthCoarse", Vector{"f"}, false, true), //
- C("fwidthFine", Vector{"f"}, false, true), //
+ true), //
+ C("textureSampleGrad", Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false, true), //
+ C("textureSampleLevel", Vector{"t2d", "s2d", "vf2", "f"}, false, true), //
+ C("transpose", Vector{"m"}, false, true), //
+ C("trunc", Vector{"f"}, false, true), //
+ C("unpack2x16float", Vector{"u"}, false, true), //
+ C("unpack2x16snorm", Vector{"u"}, false, true), //
+ C("unpack2x16unorm", Vector{"u"}, false, true), //
+ C("unpack4x8snorm", Vector{"u"}, false, true), //
+ C("unpack4x8unorm", Vector{"u"}, false, true), //
+ C("storageBarrier", tint::Empty, false, false, ast::PipelineStage::kCompute), //
+ C("workgroupBarrier", tint::Empty, false, false, ast::PipelineStage::kCompute), //
+ C("textureSample", Vector{"t2d", "s2d", "vf2"}, true, true), //
+ C("textureSampleBias", Vector{"t2d", "s2d", "vf2", "f"}, true, true), //
+ C("textureSampleCompare", Vector{"tdepth2d", "scomp", "vf2", "f"}, true, true), //
+ C("dpdx", Vector{"f"}, true, true), //
+ C("dpdxCoarse", Vector{"f"}, true, true), //
+ C("dpdxFine", Vector{"f"}, true, true), //
+ C("dpdy", Vector{"f"}, true, true), //
+ C("dpdyCoarse", Vector{"f"}, true, true), //
+ C("dpdyFine", Vector{"f"}, true, true), //
+ C("fwidth", Vector{"f"}, true, true), //
+ C("fwidthCoarse", Vector{"f"}, true, true), //
+ C("fwidthFine", Vector{"f"}, true, true), //
// Side-effect builtins
C("atomicAdd", Vector{"pa", "i"}, true, true), //
diff --git a/src/tint/utils/file/tmpfile_windows.cc b/src/tint/utils/file/tmpfile_windows.cc
index 486c2ea..d4112eb 100644
--- a/src/tint/utils/file/tmpfile_windows.cc
+++ b/src/tint/utils/file/tmpfile_windows.cc
@@ -29,6 +29,8 @@
#include "src/tint/utils/file/tmpfile.h"
+#include <fcntl.h>
+#include <io.h>
#include <stdio.h>
#include <cstdio>
@@ -42,11 +44,16 @@
// creating it, failing if it already exists.
while (tmpnam_s(name, L_tmpnam - 1) == 0) {
std::string name_with_ext = std::string(name) + ext;
- FILE* f = nullptr;
- // The "x" arg forces the function to fail if the file already exists.
- fopen_s(&f, name_with_ext.c_str(), "wbx");
- if (f) {
- fclose(f);
+
+ // Use MS-specific _sopen_s as it allows us to create the file in exclusive mode (_O_EXCL)
+ // so that it returns an error if the file already exists.
+ int fh = 0;
+ errno_t e = _sopen_s(&fh, name_with_ext.c_str(), //
+ /* _OpenFlag */ _O_RDWR | _O_CREAT | _O_EXCL, //
+ /* _ShareFlag */ _SH_DENYNO,
+ /* _PermissionMode */ _S_IREAD | _S_IWRITE);
+ if (e == 0) {
+ _close(fh);
return name_with_ext;
}
}
diff --git a/src/tint/utils/system/terminal_posix.cc b/src/tint/utils/system/terminal_posix.cc
index fb2d93f..e820774 100644
--- a/src/tint/utils/system/terminal_posix.cc
+++ b/src/tint/utils/system/terminal_posix.cc
@@ -39,6 +39,7 @@
#include <utility>
#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/system/env.h"
#include "src/tint/utils/system/terminal.h"
@@ -47,7 +48,8 @@
namespace {
std::optional<bool> TerminalIsDarkImpl(FILE* out) {
- if (!TerminalSupportsColors(out)) {
+ // Check the terminal can be queried, and supports colors.
+ if (!isatty(STDIN_FILENO) || !TerminalSupportsColors(out)) {
return std::nullopt;
}
@@ -59,17 +61,22 @@
// Store the current attributes for 'out', restore it before returning
termios original_state{};
- tcgetattr(out_fd, &original_state);
+ if (tcgetattr(out_fd, &original_state) != 0) {
+ return std::nullopt;
+ }
TINT_DEFER(tcsetattr(out_fd, TCSADRAIN, &original_state));
// Prevent echoing.
termios state = original_state;
state.c_lflag &= ~static_cast<tcflag_t>(ECHO | ICANON);
- tcsetattr(out_fd, TCSADRAIN, &state);
+ if (tcsetattr(out_fd, TCSADRAIN, &state) != 0) {
+ return std::nullopt;
+ }
// Emit the device control escape sequence to query the terminal colors.
static constexpr std::string_view kQuery = "\033]11;?\033\\";
fwrite(kQuery.data(), 1, kQuery.length(), out);
+ fflush(out);
// Timeout for attempting to read the response.
static constexpr auto kTimeout = std::chrono::milliseconds(300);
@@ -77,6 +84,22 @@
// Record the start time.
auto start = std::chrono::steady_clock::now();
+ // Returns true if there's data available on stdin, or false if no data was available after
+ // 100ms.
+ auto poll_stdin = [] {
+ // Note: These macros introduce identifiers that start with `__`.
+ TINT_BEGIN_DISABLE_WARNING(RESERVED_IDENTIFIER);
+ fd_set rfds{};
+ FD_ZERO(&rfds);
+ FD_SET(STDIN_FILENO, &rfds);
+ timeval tv{};
+ tv.tv_sec = 0;
+ tv.tv_usec = 100'000;
+ int res = select(STDIN_FILENO + 1, &rfds, nullptr, nullptr, &tv);
+ return res > 0 && FD_ISSET(STDIN_FILENO, &rfds);
+ TINT_END_DISABLE_WARNING(RESERVED_IDENTIFIER);
+ };
+
// Helpers for parsing the response.
Vector<char, 8> peek;
auto read = [&]() -> std::optional<char> {
@@ -84,6 +107,10 @@
return peek.Pop();
}
while ((std::chrono::steady_clock::now() - start) < kTimeout) {
+ if (!poll_stdin()) {
+ return std::nullopt;
+ }
+
char c;
if (fread(&c, 1, 1, stdin) == 1) {
return c;
@@ -163,7 +190,7 @@
return std::nullopt;
}
- if (!match("\x07") && !match("\x1b\x5c")) {
+ if (!match("\x07") && !match("\x1b")) {
return std::nullopt;
}