Merge pull request #1578 from antmicro/module-ports
Add helper functions for `kModulePortDeclaration`s
diff --git a/.github/bin/build-and-test.sh b/.github/bin/build-and-test.sh
index aca1978..f059ac7 100755
--- a/.github/bin/build-and-test.sh
+++ b/.github/bin/build-and-test.sh
@@ -83,6 +83,10 @@
;;
asan|asan-clang)
+ if [[ "${MODE}" == "asan" ]]; then
+ # Some gcc 12 issue with regexp it seems.
+ BAZEL_OPTS="${BAZEL_OPTS} --cxxopt=-Wno-maybe-uninitialized"
+ fi
bazel test --config=asan --cache_test_results=no --test_output=errors $BAZEL_OPTS -c fastbuild ${CHOSEN_TARGETS}
;;
@@ -98,6 +102,11 @@
bazel build --keep_going $BAZEL_OPTS :install-binaries
;;
+ compile20)
+ # Compile with C++ 20 to make sure to be compatible with the next version.
+ bazel build --keep_going $BAZEL_OPTS --cxxopt=-std=c++20 :install-binaries
+ ;;
+
smoke-test)
$(dirname $0)/smoke-test.sh
;;
diff --git a/.github/bin/github-pages-setup.sh b/.github/bin/github-pages-setup.sh
index 887b16b..d1c1bea 100755
--- a/.github/bin/github-pages-setup.sh
+++ b/.github/bin/github-pages-setup.sh
@@ -17,11 +17,21 @@
# ---------------
# Generate the GitHub pages to deploy
+set -eux
+
+BINDIR=${1:-/usr/bin}
REPO_SLUG=${REPO_SLUG:-${GITHUB_REPOSITORY_SLUG:-google/verible}}
GIT_DATE=${GIT_DATE:-$(git show -s --format=%ci)}
GIT_HASH=${GIT_HASH:-$(git rev-parse HEAD)}
GIT_VERSION=${GIT_VERSION:-$(git rev-parse --short "$GITHUB_SHA")}
+# Check if a file exists and is executable before running it.
+# Useful for running commands which return a non-zero exit code
+# despite providing meaningful output, e.g. Verible binaries with the "-helpfull" param.
+check_and_run() {
+ test -x "$1" && ($@ || true)
+}
+
echo "Git date: $GIT_DATE"
echo "Git hash: $GIT_HASH"
echo "Git version: $GIT_VERSION"
@@ -77,7 +87,7 @@
# Generate lint rules documentation
# --------------------------------
-bazel-bin/verilog/tools/lint/verible-verilog-lint -generate_markdown > $PAGES_DIR/lint.md
+${BINDIR}/verible-verilog-lint -generate_markdown > $PAGES_DIR/lint.md
cat >> $PAGES_DIR/lint.md <<EOF
## Version
@@ -97,7 +107,7 @@
## Command line arguments
\`\`\`
EOF
-bazel-bin/verilog/tools/syntax/verible-verilog-syntax -helpfull >> $SYNTAX_DOC
+check_and_run ${BINDIR}/verible-verilog-syntax -helpfull >> $SYNTAX_DOC
cat >> $SYNTAX_DOC <<EOF
\`\`\`
@@ -120,14 +130,14 @@
\`\`\`
EOF
-bazel-bin/verilog/tools/lint/verible-verilog-lint -helpfull >> $LINT_DOC
+check_and_run ${BINDIR}/verible-verilog-lint -helpfull >> $LINT_DOC
cat >> $LINT_DOC <<'EOF'
```
## Lint Rules
EOF
-bazel-bin/verilog/tools/lint/verible-verilog-lint -generate_markdown >> $LINT_DOC
+${BINDIR}/verible-verilog-lint -generate_markdown >> $LINT_DOC
cat >> $LINT_DOC <<EOF
## Version
@@ -147,7 +157,7 @@
## Command line arguments
\`\`\`
EOF
-bazel-bin/verilog/tools/formatter/verible-verilog-format -helpfull >> $FORMAT_DOC
+check_and_run ${BINDIR}/verible-verilog-format -helpfull >> $FORMAT_DOC
cat >> $FORMAT_DOC <<EOF
\`\`\`
diff --git a/.github/bin/github-releases-setup.sh b/.github/bin/github-releases-setup.sh
index 9490ab7..06ca975 100755
--- a/.github/bin/github-releases-setup.sh
+++ b/.github/bin/github-releases-setup.sh
@@ -17,8 +17,11 @@
# ---------------
# Generate the GitHub Releases to deploy
+set -ex
+
+SCRIPT_DIR=$(dirname $0)
RELEASE_DIR=${1:-/tmp/releases}
-rm -rf $RELEASE_DIR
+rm -rf "$RELEASE_DIR/*"
GIT_VERSION=${GIT_VERSION:-$(git rev-parse --short "$GITHUB_SHA")}
@@ -36,9 +39,11 @@
for BIN in $PREFIX_BIN/*; do
ls -l $BIN
file $BIN
- ldd $BIN
+ ldd $BIN || true # ignore the potential 'not a dynamic executable' errors for non-binaries
done
+${SCRIPT_DIR}/github-pages-setup.sh $PREFIX_BIN
+
# Documentation
cp -a /tmp/pages/* $PREFIX_DOC
# Man pages
diff --git a/.github/bin/install-bazel.sh b/.github/bin/install-bazel.sh
index 612456d..af67ec3 100755
--- a/.github/bin/install-bazel.sh
+++ b/.github/bin/install-bazel.sh
@@ -18,6 +18,6 @@
exit 1
fi
wget --no-verbose "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel_${BAZEL_VERSION}-linux-x86_64.deb" -O /tmp/bazel.deb
-sudo dpkg -i /tmp/bazel.deb || true
-sudo apt-get -f install
+dpkg -i /tmp/bazel.deb || true
+apt-get -f install
bazel --version
diff --git a/.github/bin/run-clang-format.sh b/.github/bin/run-clang-format.sh
index 73ac1d1..2fdfb04 100755
--- a/.github/bin/run-clang-format.sh
+++ b/.github/bin/run-clang-format.sh
@@ -24,7 +24,10 @@
if [ -s ${FORMAT_OUT} ]; then
echo "Style not matching (see https://github.com/chipsalliance/verible/blob/master/CONTRIBUTING.md#style)"
- echo "On your *.h, *.cc files, please run clang-format -i --style=file <your changed files>"
+ echo "Run"
+ echo " .github/bin/run-clang-format.sh"
+ echo "-------------------------------------------------"
+ echo
cat ${FORMAT_OUT}
exit 1
fi
diff --git a/.github/bin/set-compiler.sh b/.github/bin/set-compiler.sh
index b2c535a..99d007f 100755
--- a/.github/bin/set-compiler.sh
+++ b/.github/bin/set-compiler.sh
@@ -15,12 +15,12 @@
VERSION=$1
-sudo dpkg --list | grep gcc
-sudo dpkg --list | grep libstdc++
+dpkg --list | grep gcc
+dpkg --list | grep libstdc++
-sudo ln -sf /usr/bin/gcc-$VERSION /usr/bin/gcc
-sudo ln -sf /usr/bin/g++-$VERSION /usr/bin/g++
-sudo ln -sf /usr/bin/gcov-$VERSION /usr/bin/gcov
+ln -sf /usr/bin/gcc-$VERSION /usr/bin/gcc
+ln -sf /usr/bin/g++-$VERSION /usr/bin/g++
+ln -sf /usr/bin/gcov-$VERSION /usr/bin/gcov
gcc --version || true
gcov --version
diff --git a/.github/bin/smoke-test.sh b/.github/bin/smoke-test.sh
index bda322c..1e96d74 100755
--- a/.github/bin/smoke-test.sh
+++ b/.github/bin/smoke-test.sh
@@ -72,7 +72,7 @@
# array below, mapping them to Verible issue tracker numbers.
readonly TEST_GIT_PROJECTS="https://github.com/lowRISC/ibex \
https://github.com/lowRISC/opentitan \
- https://github.com/chipsalliance/Cores-SweRV \
+ https://github.com/chipsalliance/Cores-VeeR-EH2 \
https://github.com/openhwgroup/cva6 \
https://github.com/SymbiFlow/uvm \
https://github.com/taichi-ishitani/tnoc \
@@ -100,12 +100,11 @@
declare -A KnownIssue
#--- Opentitan
-KnownIssue[formatter:$BASE_TEST_DIR/opentitan/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi_pkg.sv]=1006
+# Original issue - 1006 has been resolved
# There is also bug 1008 which only shows up if compiled with asan
#--- ivtest
KnownIssue[formatter:$BASE_TEST_DIR/ivtest/ivltests/pr2202846c.v]=1015
-KnownIssue[formatter:$BASE_TEST_DIR/ivtest/ivltests/packed_dims_invalid_class.v]=1146
#--- nontrivial-mips
KnownIssue[formatter:$BASE_TEST_DIR/nontrivial-mips/src/cpu/decode/decoder.sv]=984
@@ -132,18 +131,19 @@
ExpectedFailCount[syntax:ibex]=14
ExpectedFailCount[lint:ibex]=14
-ExpectedFailCount[project:ibex]=189
+ExpectedFailCount[project:ibex]=192
ExpectedFailCount[syntax:opentitan]=35
ExpectedFailCount[lint:opentitan]=35
-ExpectedFailCount[formatter:opentitan]=1
-ExpectedFailCount[project:opentitan]=722
+ExpectedFailCount[project:opentitan]=727
-ExpectedFailCount[project:Cores-SweRV]=21
+ExpectedFailCount[syntax:Cores-VeeR-EH2]=2
+ExpectedFailCount[lint:Cores-VeeR-EH2]=2
+ExpectedFailCount[project:Cores-VeeR-EH2]=42
ExpectedFailCount[syntax:cva6]=4
ExpectedFailCount[lint:cva6]=4
-ExpectedFailCount[project:cva6]=25
+ExpectedFailCount[project:cva6]=70
ExpectedFailCount[syntax:uvm]=1
ExpectedFailCount[lint:uvm]=1
@@ -168,7 +168,7 @@
ExpectedFailCount[formatter:ivtest]=2
ExpectedFailCount[project:ivtest]=217
-ExpectedFailCount[project:ZAP]=30
+ExpectedFailCount[project:ZAP]=29
ExpectedFailCount[syntax:nontrivial-mips]=2
ExpectedFailCount[lint:nontrivial-mips]=2
@@ -185,9 +185,9 @@
ExpectedFailCount[formatter:scr1]=2
ExpectedFailCount[project:scr1]=45
-ExpectedFailCount[syntax:basejump_stl]=460
-ExpectedFailCount[lint:basejump_stl]=460
-ExpectedFailCount[project:basejump_stl]=566
+ExpectedFailCount[syntax:basejump_stl]=462
+ExpectedFailCount[lint:basejump_stl]=462
+ExpectedFailCount[project:basejump_stl]=569
# Ideally, we expect all tools to process all files with a zero exit code.
# However, that is not always the case, so we document the current
diff --git a/.github/workflows/verible-ci.yml b/.github/workflows/verible-ci.yml
index fadddd6..778829c 100644
--- a/.github/workflows/verible-ci.yml
+++ b/.github/workflows/verible-ci.yml
@@ -12,15 +12,18 @@
workflow_dispatch:
env:
- DOCKER_BUILDKIT: 1
BOT_USER: "Deployment Bot"
BOT_EMAIL: "verible-dev@googlegroups.com"
+ GHA_MACHINE_TYPE: "n2-standard-8"
+ DEBIAN_FRONTEND: "noninteractive"
+ VERIBLE_BINDIR: "/tmp/verible-bin"
jobs:
VerifyFormatting:
- runs-on: ubuntu-20.04
+ container: ubuntu:20.04
+ runs-on: [self-hosted, Linux, X64]
steps:
@@ -36,14 +39,26 @@
- name: Install Dependencies
run: |
- sudo apt -qq -y install clang-format
+ apt -qqy update
+ apt -qq -y install clang-format git
clang-format --version
- name: Run formatting style check
run: ./.github/bin/run-clang-format.sh
+ - name: 📤 Upload performance graphs
+ uses: actions/upload-artifact@v2
+ if: success() || failure()
+ with:
+ name: "diag"
+ path: "**/plot_*.svg"
+
ClangTidy:
- runs-on: ubuntu-20.04
+ container: ubuntu:20.04
+ runs-on: [self-hosted, Linux, X64]
+
+ env:
+ GHA_MACHINE_TYPE: "n2-standard-4"
steps:
@@ -59,7 +74,10 @@
- name: Install Dependencies
run: |
- sudo apt -qq -y install clang-tidy-11
+ apt -qqy update
+ apt -qq -y install clang-tidy-11 build-essential git wget
+ source ./.github/settings.sh
+ ./.github/bin/install-bazel.sh
echo "TMPDIR=/tmp" >> $GITHUB_ENV
- name: Create Cache Timestamp
@@ -69,20 +87,28 @@
format: 'YYYY-MM-DD-HH-mm-ss'
- name: Retrieve cached results
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
/tmp/clang-tidy-hashes.cache
- /home/runner/.cache/bazel
+ /root/.cache/bazel
key: clang-tidy-${{ steps.cache_timestamp.outputs.time }}
restore-keys: clang-tidy-
- name: Run clang tidy
run: ./.github/bin/run-clang-tidy.sh
+ - name: 📤 Upload performance graphs
+ uses: actions/upload-artifact@v2
+ if: success() || failure()
+ with:
+ name: "diag"
+ path: "**/plot_*.svg"
+
Check:
- runs-on: ubuntu-20.04
+ container: ubuntu:20.04
+ runs-on: [self-hosted, Linux, X64]
strategy:
fail-fast: false
matrix:
@@ -119,45 +145,52 @@
format: 'YYYY-MM-DD-HH-mm-ss'
- name: Mount bazel cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
if: matrix.mode != 'clean' && matrix.mode != 'coverage'
with:
- path: "/home/runner/.cache/bazel"
+ path: "/root/.cache/bazel"
key: bazelcache_${{ matrix.mode }}_${{ steps.cache_timestamp.outputs.time }}
restore-keys: bazelcache_${{ matrix.mode }}_
- name: Install Dependencies
run: |
set -x
+ apt -qqy update
+ apt -qq -y install clang-10 build-essential wget git python3 python-is-python3 gcc-10 g++-10 default-jdk
source ./.github/settings.sh
- sudo apt -qq -y install clang-10
- ./.github/bin/set-compiler.sh 9
+ ./.github/bin/set-compiler.sh 10
./.github/bin/install-bazel.sh
- name: ${{ matrix.mode }} Verible
run: ./.github/bin/build-and-test.sh
- - name: Set up things for GitHub Pages deployment
- if: matrix.mode == 'compile'
- run: ./.github/bin/github-pages-setup.sh
-
- name: Upload coverage
# will show up under https://app.codecov.io/gh/chipsalliance/verible
if: matrix.mode == 'coverage'
uses: codecov/codecov-action@v2
with:
files: bazel-out/_coverage/_coverage_report.dat
- fail_ci_if_error: true
verbose: true
+ continue-on-error: true
- - name: Deployment
- if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && matrix.mode == 'compile'
- uses: JamesIves/github-pages-deploy-action@3.7.1
+ - name: Gather and pack binaries
+ if: matrix.mode == 'compile'
+ run: bazel run :install -c fastbuild -- $VERIBLE_BINDIR && tar cfv verible-bin.tar -C $VERIBLE_BINDIR .
+
+ - name: Upload bazel-bin
+ if: matrix.mode == 'compile'
+ uses: actions/upload-artifact@v2
with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- BRANCH: gh-pages
- FOLDER: /tmp/pages
- CLEAN: true
+ name: verible-bin
+ path: verible-bin.tar
+
+
+ - name: 📤 Upload performance graphs
+ uses: actions/upload-artifact@v2
+ if: success() || failure()
+ with:
+ name: "diag"
+ path: "**/plot_*.svg"
Kythe:
@@ -207,7 +240,8 @@
Build:
needs: Matrix
- runs-on: ubuntu-20.04
+ container: debian:bullseye
+ runs-on: [self-hosted, Linux, X64]
# Github actions resources are limited; don't build artifacts for all
# platforms on every pull request, only on push.
if: ${{github.event_name == 'push'}}
@@ -217,6 +251,8 @@
include: ${{ fromJson(needs.Matrix.outputs.matrix) }}
env:
MATRIX_OS: '${{ matrix.os }}:${{ matrix.ver }}'
+ DOCKER_DATA_ROOT: "/root/.docker"
+ GHA_MACHINE_TYPE: "n2-highcpu-8"
name: 'Build · ${{ matrix.os }}:${{ matrix.ver }}'
steps:
@@ -226,11 +262,24 @@
# Download complete repository + tags
fetch-depth: 0
- - run: docker pull $MATRIX_OS
+ - name: Install and setup Docker
+ run: "apt -qqy update && apt -qqy --no-install-recommends install docker.io cgroupfs-mount crun fuse-overlayfs pigz ca-certificates git && cgroupfs-mount"
- name: Main script
run: |
set -x
+
+ mkdir -p "$DOCKER_DATA_ROOT"
+ dockerd \
+ -s fuse-overlayfs \
+ --add-runtime=crun=/usr/bin/crun \
+ --default-runtime=crun \
+ --config-file="" \
+ --data-root=$DOCKER_DATA_ROOT > /dev/null 2>&1 &
+ while ! test -S /var/run/docker.sock; do echo "Waiting for Docker..." && sleep 1; done; docker info
+ trap "kill $(cat /var/run/docker.pid)" EXIT
+
+ docker pull $MATRIX_OS
source ./.github/settings.sh
./releasing/docker-run.sh $MATRIX_OS
@@ -239,6 +288,13 @@
with:
path: releasing/out/verible-*.tar.gz
+ - name: 📤 Upload performance graphs
+ uses: actions/upload-artifact@v2
+ if: success() || failure()
+ with:
+ name: "diag"
+ path: "**/plot_*.svg"
+
MacOsBuild:
runs-on: macos-latest
steps:
@@ -254,7 +310,7 @@
format: 'YYYY-MM-DD-HH-mm-ss'
- name: Mount bazel cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: "/private/var/tmp/_bazel_runner"
key: bazelcache_macos_${{ steps.cache_timestamp.outputs.time }}
@@ -279,7 +335,7 @@
format: 'YYYY-MM-DD-HH-mm-ss'
- name: Mount bazel cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: "c:/users/runneradmin/_bazel_runneradmin"
key: bazelcache_windows2_${{ steps.cache_timestamp.outputs.time }}
@@ -356,3 +412,29 @@
tag: ${{ env.TAG }}
overwrite: true
file_glob: true
+
+ GhPages:
+ name: Build and deploy GitHub pages
+ needs: [Check]
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: actions/download-artifact@v3
+ with:
+ name: verible-bin
+
+ - name: Extract Verible binaries
+ run: mkdir -p $VERIBLE_BINDIR && tar xvf verible-bin.tar -C $VERIBLE_BINDIR
+
+ - name: Set up things for GitHub Pages deployment
+ run: ./.github/bin/github-pages-setup.sh $VERIBLE_BINDIR
+
+ - name: Deployment
+ if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && matrix.mode == 'compile'
+ uses: JamesIves/github-pages-deploy-action@3.7.1
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ BRANCH: gh-pages
+ FOLDER: /tmp/pages
+ CLEAN: true
diff --git a/README.md b/README.md
index 0f0cb5b..7c08a24 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[](https://opensource.org/licenses/Apache-2.0)
-[](https://github.com/chipsalliance/verible/actions/workflows/verible-ci.yml)
+[](https://github.com/chipsalliance/verible/actions/workflows/verible-ci.yml)
[](https://codecov.io/gh/chipsalliance/verible)
<!--*
diff --git a/WORKSPACE b/WORKSPACE
index ad7d61c..dcbc98d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -6,12 +6,25 @@
# Bazel platform rules, needed as dependency to absl.
http_archive(
name = "platforms",
- sha256 = "a879ea428c6d56ab0ec18224f976515948822451473a80d06c2e50af0bbe5121",
- strip_prefix = "platforms-da5541f26b7de1dc8e04c075c99df5351742a4a2",
- urls = ["https://github.com/bazelbuild/platforms/archive/da5541f26b7de1dc8e04c075c99df5351742a4a2.zip"], # 2022-05-27
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz",
+ "https://github.com/bazelbuild/platforms/releases/download/0.0.6/platforms-0.0.6.tar.gz",
+ ],
+ sha256 = "5308fc1d8865406a49427ba24a9ab53087f17f5266a7aabbfc28823f3916e1ca",
)
http_archive(
+ name = "bazel_skylib",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.3.0/bazel-skylib-1.3.0.tar.gz",
+ ],
+ sha256 = "74d544d96f4a5bb630d465ca8bbcfe231e3594e5aae57e1edbf17a6eb3ca2506",
+)
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+bazel_skylib_workspace()
+
+http_archive(
name = "com_google_absl",
# On MSVC's STL implementation, string_view cannot be constructed from
# a string_view::iterator. This patch forces the use of absl's string_view
@@ -74,9 +87,9 @@
win_flex_configure(
name = "win_flex_bison",
- sha256 = "095cf65cb3f12ee5888022f93109acbe6264e5f18f6ffce0bda77feb31b65bd8",
- # bison 3.3.2, flex 2.6.4
- url = "https://github.com/lexxmark/winflexbison/releases/download/v2.5.18/win_flex_bison-2.5.18.zip",
+ sha256 = "8d324b62be33604b2c45ad1dd34ab93d722534448f55a16ca7292de32b6ac135",
+ # bison 3.8.2, flex 2.6.4
+ url = "https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip",
)
http_archive(
@@ -113,10 +126,10 @@
# A version slightly beyond 21.5 as it fixes a warning
http_archive(
name = "com_google_protobuf",
- sha256 = "efcd93bb1a228d08b4b0fcda00e710592fdf17ce6d0f5c8a239c2db0ba268a3f",
- strip_prefix = "protobuf-4efbcc44605731dc31507b94f0b81d2bd5ec169b",
+ sha256 = "6a31b662deaeb0ac35e6287bda2f3369b19836e6c9f8828d4da444346f420298",
+ strip_prefix = "protobuf-21.12",
urls = [
- "https://github.com/protocolbuffers/protobuf/archive/4efbcc44605731dc31507b94f0b81d2bd5ec169b.zip",
+ "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v21.12.zip",
],
)
diff --git a/common/formatting/layout_optimizer.cc b/common/formatting/layout_optimizer.cc
index ee18ab7..39e599d 100644
--- a/common/formatting/layout_optimizer.cc
+++ b/common/formatting/layout_optimizer.cc
@@ -570,10 +570,14 @@
}
}
}
+ // std::max(hanging_indentation, 0) serves to resolve a case where
+ // the subsequent nodes will try to be indented below zero following
+ // a less-indented token eg. a macro
const int hanging_indentation =
(node.Children().size() > 1)
- ? (node.Children()[1].Value().IndentationSpaces() -
- node.Value().IndentationSpaces())
+ ? std::max(node.Children()[1].Value().IndentationSpaces() -
+ node.Value().IndentationSpaces(),
+ 0)
: 0;
return factory_.Wrap(layouts.begin(), layouts.end(), false,
diff --git a/releasing/build.sh b/releasing/build.sh
index 2263203..008fd97 100755
--- a/releasing/build.sh
+++ b/releasing/build.sh
@@ -18,5 +18,4 @@
cd $(dirname "$0")/..
-./.github/bin/github-pages-setup.sh
./.github/bin/github-releases-setup.sh /out
diff --git a/verilog/analysis/symbol_table.cc b/verilog/analysis/symbol_table.cc
index 9c804e3..3ee0ab4 100644
--- a/verilog/analysis/symbol_table.cc
+++ b/verilog/analysis/symbol_table.cc
@@ -909,12 +909,8 @@
SymbolTableNode* EmplaceElementInCurrentScope(const verible::Symbol& element,
absl::string_view name,
SymbolMetaType metatype) {
- const auto p =
- current_scope_->TryEmplace(name, SymbolInfo{
- .metatype = metatype,
- .file_origin = source_,
- .syntax_origin = &element,
- });
+ const auto p = current_scope_->TryEmplace(
+ name, SymbolInfo{metatype, source_, &element});
if (!p.second) {
DiagnoseSymbolAlreadyExists(name, p.first->first);
}
@@ -931,14 +927,11 @@
VLOG(1) << " type info: " << *ABSL_DIE_IF_NULL(declaration_type_info_);
VLOG(1) << " full text: " << AutoTruncate{StringSpanOfSymbol(element), 40};
const auto p = current_scope_->TryEmplace(
- name,
- SymbolInfo{
- .metatype = metatype,
- .file_origin = source_,
- .syntax_origin = &element,
- // associate this instance with its declared type
- .declared_type = *ABSL_DIE_IF_NULL(declaration_type_info_), // copy
- });
+ name, SymbolInfo{
+ metatype, source_, &element,
+ // associate this instance with its declared type
+ *ABSL_DIE_IF_NULL(declaration_type_info_), // copy
+ });
if (!p.second) {
DiagnoseSymbolAlreadyExists(name, p.first->first);
}
@@ -1253,11 +1246,7 @@
const absl::string_view inner_key = inner_ref.identifier;
const auto p = outer_scope->TryEmplace(
- inner_key, SymbolInfo{
- .metatype = metatype,
- .file_origin = source_,
- .syntax_origin = definition_syntax,
- });
+ inner_key, SymbolInfo{metatype, source_, definition_syntax});
SymbolTableNode* inner_symbol = &p.first->second;
if (p.second) {
// If injection succeeded, then the outer_scope did not already contain a
diff --git a/verilog/analysis/symbol_table.h b/verilog/analysis/symbol_table.h
index 486b566..1cc5ef1 100644
--- a/verilog/analysis/symbol_table.h
+++ b/verilog/analysis/symbol_table.h
@@ -180,6 +180,9 @@
public:
DependentReferences() = default;
+ explicit DependentReferences(
+ std::unique_ptr<ReferenceComponentNode> components)
+ : components(std::move(components)) {}
// move-only
DependentReferences(const DependentReferences&) = delete;
DependentReferences(DependentReferences&&) = default;
@@ -251,14 +254,6 @@
bool implicit = false;
public:
- DeclarationTypeInfo() = default;
-
- // copy-able, move-able, assignable
- DeclarationTypeInfo(const DeclarationTypeInfo&) = default;
- DeclarationTypeInfo(DeclarationTypeInfo&&) = default;
- DeclarationTypeInfo& operator=(const DeclarationTypeInfo&) = default;
- DeclarationTypeInfo& operator=(DeclarationTypeInfo&&) = default;
-
// Structural consistency check.
void VerifySymbolTableRoot(const SymbolTableNode* root) const;
};
@@ -328,6 +323,13 @@
public: // methods
SymbolInfo() = default;
+ SymbolInfo(SymbolMetaType metatype, const VerilogSourceFile* file_origin = {},
+ const verible::Symbol* syntax_origin = {},
+ DeclarationTypeInfo declared_type = {})
+ : metatype(metatype),
+ file_origin(file_origin),
+ syntax_origin(syntax_origin),
+ declared_type(declared_type) {}
// move-only
SymbolInfo(const SymbolInfo&) = delete;
@@ -422,7 +424,7 @@
// and string memory, otherwise string memory is owned by 'project'.
explicit SymbolTable(VerilogProject* project)
: project_(project),
- symbol_table_root_(SymbolInfo{.metatype = SymbolMetaType::kRoot}) {}
+ symbol_table_root_(SymbolInfo{SymbolMetaType::kRoot}) {}
// can become move-able when needed
SymbolTable(const SymbolTable&) = delete;
diff --git a/verilog/analysis/symbol_table_test.cc b/verilog/analysis/symbol_table_test.cc
index 27864d3..444fcc5 100644
--- a/verilog/analysis/symbol_table_test.cc
+++ b/verilog/analysis/symbol_table_test.cc
@@ -245,12 +245,11 @@
}
TEST(DependentReferencesTest, PrintOnlyRootNodeUnresolved) {
- const DependentReferences dep_refs{
- .components = std::make_unique<ReferenceComponentNode>(
- ReferenceComponent{.identifier = "foo",
- .ref_type = ReferenceType::kUnqualified,
- .required_metatype = SymbolMetaType::kUnspecified,
- .resolved_symbol = nullptr})};
+ const DependentReferences dep_refs{std::make_unique<ReferenceComponentNode>(
+ ReferenceComponent{.identifier = "foo",
+ .ref_type = ReferenceType::kUnqualified,
+ .required_metatype = SymbolMetaType::kUnspecified,
+ .resolved_symbol = nullptr})};
std::ostringstream stream;
stream << dep_refs;
EXPECT_EQ(stream.str(), "{ (@foo -> <unresolved>) }");
@@ -260,29 +259,27 @@
// Synthesize a symbol table.
typedef SymbolTableNode::key_value_type KV;
SymbolTableNode root(
- SymbolInfo{.metatype = SymbolMetaType::kRoot},
+ SymbolInfo{SymbolMetaType::kRoot},
KV{"p_pkg",
- SymbolTableNode(
- SymbolInfo{.metatype = SymbolMetaType::kPackage},
- KV{"c_class", SymbolTableNode(SymbolInfo{
- .metatype = SymbolMetaType::kClass})})});
+ SymbolTableNode(SymbolInfo{SymbolMetaType::kPackage},
+ KV{"c_class", SymbolTableNode(SymbolInfo{
+ SymbolMetaType::kClass})})});
// Bookmark symbol table nodes.
MUST_ASSIGN_LOOKUP_SYMBOL(p_pkg, root, "p_pkg");
MUST_ASSIGN_LOOKUP_SYMBOL(c_class, p_pkg, "c_class");
// Construct references already resolved to above nodes.
- const DependentReferences dep_refs{
- .components = std::make_unique<ReferenceComponentNode>(
- ReferenceComponent{.identifier = "p_pkg",
- .ref_type = ReferenceType::kUnqualified,
- .required_metatype = SymbolMetaType::kPackage,
- .resolved_symbol = &p_pkg},
- ReferenceComponentNode(
- ReferenceComponent{.identifier = "c_class",
- .ref_type = ReferenceType::kDirectMember,
- .required_metatype = SymbolMetaType::kClass,
- .resolved_symbol = &c_class}))};
+ const DependentReferences dep_refs{std::make_unique<ReferenceComponentNode>(
+ ReferenceComponent{.identifier = "p_pkg",
+ .ref_type = ReferenceType::kUnqualified,
+ .required_metatype = SymbolMetaType::kPackage,
+ .resolved_symbol = &p_pkg},
+ ReferenceComponentNode(
+ ReferenceComponent{.identifier = "c_class",
+ .ref_type = ReferenceType::kDirectMember,
+ .required_metatype = SymbolMetaType::kClass,
+ .resolved_symbol = &c_class}))};
// Print and compare.
std::ostringstream stream;
@@ -398,12 +395,11 @@
// symbol_table1 will outlive symbol_table_2, so give symbol_table_2 a
// pointer to symbol_table_1.
root2.Value().local_references_to_bind.push_back(DependentReferences{
- .components =
- std::make_unique<ReferenceComponentNode>(ReferenceComponent{
- .identifier = "foo",
- .ref_type = ReferenceType::kUnqualified,
- .required_metatype = SymbolMetaType::kUnspecified,
- .resolved_symbol = &root1})});
+ std::make_unique<ReferenceComponentNode>(ReferenceComponent{
+ .identifier = "foo",
+ .ref_type = ReferenceType::kUnqualified,
+ .required_metatype = SymbolMetaType::kUnspecified,
+ .resolved_symbol = &root1})});
// CheckIntegrity() will fail on destruction of symbol_table_2.
};
EXPECT_DEATH(test_func(),
@@ -421,12 +417,11 @@
// symbol_table1 will outlive symbol_table_2, so give symbol_table_2 a
// pointer to symbol_table_1.
root1.Value().local_references_to_bind.push_back(DependentReferences{
- .components =
- std::make_unique<ReferenceComponentNode>(ReferenceComponent{
- .identifier = "foo",
- .ref_type = ReferenceType::kUnqualified,
- .required_metatype = SymbolMetaType::kUnspecified,
- .resolved_symbol = &root1})});
+ std::make_unique<ReferenceComponentNode>(ReferenceComponent{
+ .identifier = "foo",
+ .ref_type = ReferenceType::kUnqualified,
+ .required_metatype = SymbolMetaType::kUnspecified,
+ .resolved_symbol = &root1})});
root2.Value().declared_type.user_defined_type =
root1.Value().local_references_to_bind.front().components.get();
// CheckIntegrity() will fail on destruction of symbol_table_2.
diff --git a/verilog/formatting/align.cc b/verilog/formatting/align.cc
index de82da2..c9294c0 100644
--- a/verilog/formatting/align.cc
+++ b/verilog/formatting/align.cc
@@ -733,6 +733,7 @@
ReserveNewColumn(node, FlushLeft);
break;
}
+ case NodeEnum::kNetDeclarationAssignment:
case NodeEnum::kNetVariable: {
// at path [2,0] in kNetDeclaration
// contains the declared id
@@ -823,6 +824,15 @@
VLOG(2) << __FUNCTION__ << ", node: " << tag << " at "
<< TreePathFormatter(Path());
switch (tag) {
+ case NodeEnum::kDeclarationDimensions: {
+ if (current_path_ == SyntaxTreePath{1, 0, 0, 3, 0}) {
+ SyntaxTreePath new_path{1, 0, 0, 3};
+ const ValueSaver<SyntaxTreePath> path_saver(¤t_path_, new_path);
+ TreeContextPathVisitor::Visit(node);
+ return;
+ }
+ break;
+ }
case NodeEnum::kDataDeclaration:
case NodeEnum::kVariableDeclarationAssignment: {
// Don't wait for the type node, just start the first column right away.
diff --git a/verilog/formatting/formatter_test.cc b/verilog/formatting/formatter_test.cc
index b0cf132..411e583 100644
--- a/verilog/formatting/formatter_test.cc
+++ b/verilog/formatting/formatter_test.cc
@@ -434,6 +434,10 @@
" aaaa == zzz;\n"
" ggg == vv::w;,\n"
" \"Failed to ..........\")\n"},
+ {// macro call nested with function call containing an ifdef
+ "`J(D(`ifdef e))\n",
+ "`J(D(\n"
+ " `ifdef e))\n"},
// `uvm macros indenting
{
@@ -3407,6 +3411,20 @@
" );\n"
"endmodule\n",
},
+ {// Two consecutive EOL comments in kDPIImportItem
+ "import \"DPI-C\" context function void foo(\n"
+ " input bit first,\n"
+ " // c3\n"
+ " // c3+\n"
+ " input bit second\n"
+ ");\n",
+ "import \"DPI-C\" context\n"
+ " function void foo(\n"
+ " input bit first,\n"
+ " // c3\n"
+ " // c3+\n"
+ " input bit second\n"
+ ");\n"},
{"import \"DPI-C\" context function void func(input bit impl_i,"
"input bit op_i,"
"input bit [5:0] mode_i,"
@@ -3426,7 +3444,7 @@
" input bit [7:0] data_i [],\n"
" output bit [7:0] data_o []\n"
");\n"},
- {// module with system task call
+ {// module with system task call w or w/o parentheses
"module m; initial begin #10 $display(\"foo\"); $display(\"bar\");"
"end endmodule",
"module m;\n"
@@ -3435,6 +3453,15 @@
" $display(\"bar\");\n"
" end\n"
"endmodule\n"},
+ {// module with system task call
+ "module m; initial begin #10 $display; $display;"
+ "end endmodule",
+ "module m;\n"
+ " initial begin\n"
+ " #10 $display;\n"
+ " $display;\n"
+ " end\n"
+ "endmodule\n"},
// interface test cases
{// two interface declarations
@@ -4299,6 +4326,21 @@
" endfunction\n"
" endclass\n"
"endpackage\n"},
+ {"package fedex;\n"
+ " import \"asdf\" context function void bar(\n"
+ " input bit [2:1] aaaa, // EOL COMMENT\n"
+ " // another\n"
+ " input bit foo\n"
+ " );\n"
+ "endpackage\n",
+ "package fedex;\n"
+ " import \"asdf\" context\n"
+ " function void bar(\n"
+ " input\n bit [2:1] aaaa, // EOL COMMENT\n"
+ " // another\n"
+ " input bit foo\n"
+ " );\n"
+ "endpackage\n"},
// function test cases
{"function f ;endfunction", "function f;\nendfunction\n"},
@@ -5475,6 +5517,43 @@
" );\n"
"endmodule\n"},
+ {// comment following a delay in next line
+ "module t;\n"
+ "reg x;\n"
+ "initial begin\n"
+ "#20\n"
+ "//comment\n"
+ "x = 1;\n"
+ "x = 2;\n"
+ "end\n"
+ "endmodule\n",
+ "module t;\n"
+ " reg x;\n"
+ " initial begin\n"
+ " #20\n"
+ " //comment\n"
+ " x = 1;\n"
+ " x = 2;\n"
+ " end\n"
+ "endmodule\n"},
+ {// comment following a delay in the same line
+ "module t;\n"
+ "reg x;\n"
+ "initial begin\n"
+ "#20 //comment\n"
+ "x = 1;\n"
+ "x = 2;\n"
+ "end\n"
+ "endmodule\n",
+ "module t;\n"
+ " reg x;\n"
+ " initial begin\n"
+ " #20 //comment\n"
+ " x = 1;\n"
+ " x = 2;\n"
+ " end\n"
+ "endmodule\n"},
+
{
// test that alternate top-syntax mode works
"// verilog_syntax: parse-as-module-body\n"
@@ -5588,6 +5667,13 @@
" .rst (rst),\n"
" .value(value)\n"
");\n"},
+ {"bind foo bar baz(\\\n"
+ "`undef d\\\n"
+ "`undef d);",
+ "bind foo bar baz (\\\n"
+ " `undef d\\\n"
+ " `undef d\n"
+ ");\n"},
{
"bind expaaaaaaaaaaand_meeee looooooooong_name# ("
".W(W_CONST), .H(H_CONST), .D(D_CONST) )"
@@ -8049,6 +8135,19 @@
" generic_type_name_t third // c\n"
";\n"
"} type_t;\n"},
+ {"struct {logic test1; // c\n"
+ "logic test2;} test3;\n",
+ "struct {\n"
+ " logic test1; // c\n"
+ " logic test2;\n"
+ "} test3;\n"},
+ {"struct {\n"
+ " /* t */ logic test1; /* t */\n"
+ "/* t */ logic test2; }test3;\n",
+ "struct {\n"
+ " /* t */ logic test1; /* t */\n"
+ " /* t */ logic test2;\n"
+ "} test3;\n"},
// Continuation comment alignment
{"`define BAR 1 // A\n"
"module foo(); // B\n"
@@ -15182,6 +15281,60 @@
"; // c1\n"
" // c2\n"
" // c3\n"},
+ {"module indent();\n"
+ " reg a;\n"
+ " reg [32:0] b;\n"
+ " wire c;\n"
+ " wire d = e ? kFoo : kBar;\n"
+ "endmodule\n",
+ "module indent ();\n"
+ " reg a;\n"
+ " reg [32:0] b;\n"
+ " wire c;\n"
+ " wire d = e ? kFoo : kBar;\n"
+ "endmodule\n"},
+
+ {"class C; T1 b; logic [$] a; T1 [$] c; endclass\n",
+ "class C;\n"
+ " T1 b;\n"
+ " logic [$] a;\n"
+ " T1 [$] c;\n"
+ "endclass\n"},
+ {"class C;\n"
+ " T1 b; //test\n"
+ " logic [$] a; //test\n"
+ " T1 [$] c; //test\n"
+ "endclass\n",
+ "class C;\n"
+ " T1 b; //test\n"
+ " logic [$] a; //test\n"
+ " T1 [$] c; //test\n"
+ "endclass\n"},
+ {"class C;\n"
+ " T1\n"
+ " b;\n"
+ " logic\n"
+ " [$]\n"
+ " a;\n"
+ " T1\n"
+ " [$]\n"
+ " c;\n"
+ "endclass\n",
+ "class C;\n"
+ " T1 b;\n"
+ " logic [$] a;\n"
+ " T1 [$] c;\n"
+ "endclass\n"},
+ {"class C;\n"
+ " logic/*t*/ [0 : 1] /*t*/\n"
+ " a;/*t*/\n"
+ " T1/*t*/[0 : 1]/*t*/\n"
+ " c;/*t*/\n"
+ "endclass\n",
+ "class C;\n"
+ " logic/*t*/ [0 : 1] /*t*/ a; /*t*/\n"
+ " T1/*t*/ [0 : 1] /*t*/ c; /*t*/\n"
+ "endclass\n"},
// -----------------------------------------------------------------
};
diff --git a/verilog/formatting/tree_unwrapper.cc b/verilog/formatting/tree_unwrapper.cc
index c71f9a5..5bd857a 100644
--- a/verilog/formatting/tree_unwrapper.cc
+++ b/verilog/formatting/tree_unwrapper.cc
@@ -469,7 +469,8 @@
while (!NextUnfilteredToken()->isEOF()) {
EatSpaces();
VLOG(4) << "lookahead token: " << VerboseToken(*NextUnfilteredToken());
- if (IsComment(verilog_tokentype(NextUnfilteredToken()->token_enum()))) {
+ if (auto next_tok = verilog_tokentype(NextUnfilteredToken()->token_enum());
+ IsComment(next_tok) || next_tok == verilog_tokentype::TK_LINE_CONT) {
// TODO(fangism): or IsAttribute(). Basically, any token that is not
// in the syntax tree and not a space.
AdvanceLastVisitedLeaf();
@@ -563,7 +564,7 @@
case NodeEnum::kPortDeclarationList:
case NodeEnum::kActualParameterByNameList:
case NodeEnum::kPortActualList:
- // case NodeEnum::kPortList: // TODO(fangism): for task/function ports
+ case NodeEnum::kPortList:
case NodeEnum::kModuleItemList:
case NodeEnum::kGenerateItemList:
case NodeEnum::kClassItems:
@@ -970,9 +971,11 @@
{
// Single statements directly inside a flow-control construct
// should be properly indented one level.
- const int indent = ShouldIndentRelativeToDirectParent(Context())
- ? style_.indentation_spaces
- : 0;
+ const int indent = Context().IsInside(NodeEnum::kBlockItemStatementList)
+ ? 0
+ : ShouldIndentRelativeToDirectParent(Context())
+ ? style_.indentation_spaces
+ : 0;
VisitIndentedSection(node, indent,
PartitionPolicyEnum::kFitOnLineElseExpand);
break;
@@ -2060,8 +2063,9 @@
paren_group_ = FindDirectChild(main_node_,
OriginTagIs{NodeTag(NodeEnum::kParenGroup)});
+
+ // Macro can be used without parentheses
if (!paren_group_) {
- LOG_PARTITION_BUG("paren_group not found.");
return false;
}
@@ -2872,7 +2876,8 @@
// RHS may have been further partitioned, e.g. a macro call.
auto& children = partition.Children();
if (children.size() == 2 &&
- verible::is_leaf(children.front()) /* left side */) {
+ verible::is_leaf(children.front()) /* left side */ &&
+ !PartitionIsForcedIntoNewLine(children.back())) {
verible::MergeLeafIntoNextLeaf(&children.front());
VLOG(4) << "after merge leaf (left-into-right):\n" << partition;
}
diff --git a/verilog/tools/ls/BUILD b/verilog/tools/ls/BUILD
index fe67b55..0cf92d1 100644
--- a/verilog/tools/ls/BUILD
+++ b/verilog/tools/ls/BUILD
@@ -62,16 +62,29 @@
],
)
-cc_binary(
- name = "verible-verilog-ls",
- srcs = ["verilog_ls.cc"],
+cc_library(
+ name = "verilog-language-server",
+ srcs = ["verilog-language-server.cc"],
+ hdrs = ["verilog-language-server.h"],
visibility = ["//visibility:public"],
deps = [
":lsp-parse-buffer",
":verible-lsp-adapter",
"//common/lsp:json-rpc-dispatcher",
"//common/lsp:lsp-protocol",
+ "//common/lsp:lsp-text-buffer",
"//common/lsp:message-stream-splitter",
+ "@com_google_absl//absl/status",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
+cc_binary(
+ name = "verible-verilog-ls",
+ srcs = ["verilog_ls.cc"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":verilog-language-server",
"//common/util:init_command_line",
],
)
diff --git a/verilog/tools/ls/verilog-language-server.cc b/verilog/tools/ls/verilog-language-server.cc
new file mode 100644
index 0000000..8f3ef14
--- /dev/null
+++ b/verilog/tools/ls/verilog-language-server.cc
@@ -0,0 +1,171 @@
+// Copyright 2021-2022 The Verible Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "verilog/tools/ls/verilog-language-server.h"
+
+#include <functional>
+
+#include "absl/strings/string_view.h"
+#include "common/lsp/lsp-protocol.h"
+#include "verilog/tools/ls/verible-lsp-adapter.h"
+
+namespace verilog {
+
+VerilogLanguageServer::VerilogLanguageServer(const WriteFun &write_fun)
+ : dispatcher_(write_fun), buffers_(&dispatcher_) {
+ // All bodies the stream splitter extracts are pushed to the json dispatcher
+ stream_splitter_.SetMessageProcessor(
+ [this](absl::string_view header, absl::string_view body) {
+ return dispatcher_.DispatchMessage(body);
+ });
+
+ // Whenever there is a new parse result ready, use that as an opportunity
+ // to send diagnostics to the client.
+ buffers_.SetChangeListener(parsed_buffers_.GetSubscriptionCallback());
+ parsed_buffers_.SetChangeListener(
+ [this](const std::string &uri,
+ const verilog::BufferTracker &buffer_tracker) {
+ SendDiagnostics(uri, buffer_tracker);
+ });
+ SetRequestHandlers();
+}
+
+void VerilogLanguageServer::SetRequestHandlers() {
+ // Exchange of capabilities.
+ dispatcher_.AddRequestHandler("initialize",
+ [this](const nlohmann::json ¶ms) {
+ return InitializeRequestHandler(params);
+ });
+
+ dispatcher_.AddRequestHandler( // Provide diagnostics on request
+ "textDocument/diagnostic",
+ [this](const verible::lsp::DocumentDiagnosticParams &p) {
+ return verilog::GenerateDiagnosticReport(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+
+ dispatcher_.AddRequestHandler( // Provide autofixes
+ "textDocument/codeAction",
+ [this](const verible::lsp::CodeActionParams &p) {
+ return verilog::GenerateLinterCodeActions(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+
+ dispatcher_.AddRequestHandler( // Provide document outline/index
+ "textDocument/documentSymbol",
+ [this](const verible::lsp::DocumentSymbolParams &p) {
+ return verilog::CreateDocumentSymbolOutline(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+
+ dispatcher_.AddRequestHandler( // Highlight related symbols under cursor
+ "textDocument/documentHighlight",
+ [this](const verible::lsp::DocumentHighlightParams &p) {
+ return verilog::CreateHighlightRanges(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+
+ dispatcher_.AddRequestHandler( // format range of file
+ "textDocument/rangeFormatting",
+ [this](const verible::lsp::DocumentFormattingParams &p) {
+ return verilog::FormatRange(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+ dispatcher_.AddRequestHandler( // format entire file
+ "textDocument/formatting",
+ [this](const verible::lsp::DocumentFormattingParams &p) {
+ return verilog::FormatRange(
+ parsed_buffers_.FindBufferTrackerOrNull(p.textDocument.uri), p);
+ });
+ // The client sends a request to shut down. Use that to exit our loop.
+ dispatcher_.AddRequestHandler("shutdown", [this](const nlohmann::json &) {
+ shutdown_requested_ = true;
+ return nullptr;
+ });
+}
+
+absl::Status VerilogLanguageServer::Run(const ReadFun &read_fun) {
+ shutdown_requested_ = false;
+ absl::Status status = absl::OkStatus();
+ while (status.ok() && !shutdown_requested_) {
+ status = stream_splitter_.PullFrom(read_fun);
+ }
+ return status;
+}
+
+void VerilogLanguageServer::PrintStatistics() const {
+ if (shutdown_requested_) {
+ std::cerr << "Shutting down due to shutdown request." << std::endl;
+ }
+
+ std::cerr << "Statistics" << std::endl;
+ std::cerr << "Largest message seen: "
+ << stream_splitter_.StatLargestBodySeen() / 1024 << " kiB "
+ << std::endl;
+ for (const auto &stats : dispatcher_.GetStatCounters()) {
+ fprintf(stderr, "%30s %9d\n", stats.first.c_str(), stats.second);
+ }
+}
+
+verible::lsp::InitializeResult VerilogLanguageServer::InitializeRequestHandler(
+ const nlohmann::json ¶ms) const {
+ // Ignore passed client capabilities from params right now,
+ // just announce what we do.
+ verible::lsp::InitializeResult result;
+ result.serverInfo = {
+ .name = "Verible Verilog language server.",
+ .version = GetVersionNumber(),
+ };
+ result.capabilities = {
+ {
+ "textDocumentSync",
+ {
+ {"openClose", true}, // Want open/close events
+ {"change", 2}, // Incremental updates
+ },
+ },
+ {"codeActionProvider", true}, // Autofixes for lint errors
+ {"documentSymbolProvider", true}, // Symbol-outline of file
+ {"documentRangeFormattingProvider", true}, // Format selection
+ {"documentFormattingProvider", true}, // Full file format
+ {"documentHighlightProvider", true}, // Highlight same symbol
+ {"diagnosticProvider", // Pull model of diagnostics.
+ {
+ {"interFileDependencies", false},
+ {"workspaceDiagnostics", false},
+ }},
+ };
+
+ return result;
+}
+
+void VerilogLanguageServer::SendDiagnostics(
+ const std::string &uri, const verilog::BufferTracker &buffer_tracker) {
+ // TODO(hzeller): Cache result and rate-limit.
+ // This should not send anything if the diagnostics we're about to
+ // send would be exactly the same as last time.
+ verible::lsp::PublishDiagnosticsParams params;
+
+ // For the diagnostic notification (that we send somewhat unsolicited), we
+ // limit the number of diagnostic messages. In the
+ // textDocument/diagnostic RPC request, we send all of them.
+ // Arbitrary limit here. Maybe set with flag ?
+ static constexpr int kDiagnosticLimit = 500;
+ params.uri = uri;
+ params.diagnostics =
+ verilog::CreateDiagnostics(buffer_tracker, kDiagnosticLimit);
+ dispatcher_.SendNotification("textDocument/publishDiagnostics", params);
+}
+
+}; // namespace verilog
diff --git a/verilog/tools/ls/verilog-language-server.h b/verilog/tools/ls/verilog-language-server.h
new file mode 100644
index 0000000..ed2fdde
--- /dev/null
+++ b/verilog/tools/ls/verilog-language-server.h
@@ -0,0 +1,72 @@
+// Copyright 2021-2022 The Verible Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef VERILOG_TOOLS_LS_LS_WRAPPER_H
+#define VERILOG_TOOLS_LS_LS_WRAPPER_H
+
+#include "absl/status/status.h"
+#include "common/lsp/json-rpc-dispatcher.h"
+#include "common/lsp/lsp-text-buffer.h"
+#include "common/lsp/message-stream-splitter.h"
+#include "verilog/tools/ls/lsp-parse-buffer.h"
+
+namespace verilog {
+
+// Class implementing the Language Server for Verilog
+class VerilogLanguageServer {
+ public:
+ using ReadFun = verible::lsp::MessageStreamSplitter::ReadFun;
+ using WriteFun = verible::lsp::JsonRpcDispatcher::WriteFun;
+
+ static std::string GetVersionNumber() { return "0.0 alpha"; }
+
+ // Constructor preparing the callbacks for Language Server requests
+ VerilogLanguageServer(const WriteFun &write_fun);
+
+ // Runs the Language Server
+ absl::Status Run(const ReadFun &read_fun);
+
+ // Prints statistics of the current Language Server session
+ void PrintStatistics() const;
+
+ private:
+ // Creates callbacks for requests from Language Server Client
+ void SetRequestHandlers();
+
+ // The "initialize" method requests server capabilities.
+ verible::lsp::InitializeResult InitializeRequestHandler(
+ const nlohmann::json ¶ms) const;
+
+ // Publish a diagnostic sent to the server.
+ void SendDiagnostics(const std::string &uri,
+ const verilog::BufferTracker &buffer_tracker);
+
+ // Stream splitter splits the input stream into messages (header/body).
+ verible::lsp::MessageStreamSplitter stream_splitter_;
+
+ // Parser for JSON messages from LS client
+ verible::lsp::JsonRpcDispatcher dispatcher_;
+
+ // Object for keeping track of updates in opened buffers on client's side
+ verible::lsp::BufferCollection buffers_;
+
+ // Tracks changes in buffers from BufferCollection and parses their contents
+ verilog::BufferTrackerContainer parsed_buffers_;
+
+ // A flag for indicating "shutdown" request
+ bool shutdown_requested_ = false;
+};
+
+}; // namespace verilog
+#endif // VERILOG_TOOLS_LS_LS_WRAPPER_H
diff --git a/verilog/tools/ls/verilog_ls.cc b/verilog/tools/ls/verilog_ls.cc
index 3656850..b50974f 100644
--- a/verilog/tools/ls/verilog_ls.cc
+++ b/verilog/tools/ls/verilog_ls.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Verible Authors.
+// Copyright 2021-2022 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,17 +13,13 @@
// limitations under the License.
//
+#include <functional>
#include <iomanip> // Only needed for json debugging right now
#include <iostream>
-#include "common/lsp/json-rpc-dispatcher.h"
-#include "common/lsp/lsp-protocol.h"
-#include "common/lsp/message-stream-splitter.h"
#include "common/util/init_command_line.h"
-#include "verilog/tools/ls/lsp-parse-buffer.h"
-#include "verilog/tools/ls/verible-lsp-adapter.h"
+#include "verilog/tools/ls/verilog-language-server.h"
-// Windows specific implementation of read()
#ifndef _WIN32
#include <unistd.h>
#else
@@ -34,187 +30,34 @@
#define read(fd, buf, size) _read(fd, buf, size)
#endif
-using nlohmann::json;
-using verible::lsp::BufferCollection;
-using verible::lsp::InitializeResult;
-using verible::lsp::JsonRpcDispatcher;
-using verible::lsp::MessageStreamSplitter;
-
-static std::string GetVersionNumber() {
- return "0.0 alpha"; // TODO(hzeller): once ready, extract from build version
-}
-
-// The "initialize" method requests server capabilities.
-static InitializeResult InitializeServer(const nlohmann::json ¶ms) {
- // Ignore passed client capabilities from params right now,
- // just announce what we do.
- InitializeResult result;
- result.serverInfo = {
- .name = "Verible Verilog language server.",
- .version = GetVersionNumber(),
- };
- result.capabilities = {
- {
- "textDocumentSync",
- {
- {"openClose", true}, // Want open/close events
- {"change", 2}, // Incremental updates
- },
- },
- {"codeActionProvider", true}, // Autofixes for lint errors
- {"documentSymbolProvider", true}, // Symbol-outline of file
- {"documentRangeFormattingProvider", true}, // Format selection
- {"documentFormattingProvider", true}, // Full file format
- {"documentHighlightProvider", true}, // Highlight same symbol
- {"diagnosticProvider", // Pull model of diagnostics.
- {
- {"interFileDependencies", false},
- {"workspaceDiagnostics", false},
- }},
- };
-
- return result;
-}
-
-// Publish a diagnostic sent to the server.
-static void SendDiagnostics(const std::string &uri,
- const verilog::BufferTracker &buffer_tracker,
- JsonRpcDispatcher *dispatcher) {
- // TODO(hzeller): Cache result and rate-limit.
- // This should not send anything if the diagnostics we're about to
- // send would be exactly the same as last time.
- verible::lsp::PublishDiagnosticsParams params;
-
- // For the diagnostic notification (that we send somewhat unsolicited), we
- // limit the number of diagnostic messages. In the
- // textDocument/diagnostic RPC request, we send all of them.
- // Arbitrary limit here. Maybe set with flag ?
- static constexpr int kDiagnosticLimit = 500;
- params.uri = uri;
- params.diagnostics =
- verilog::CreateDiagnostics(buffer_tracker, kDiagnosticLimit);
- dispatcher->SendNotification("textDocument/publishDiagnostics", params);
+static void FormatHeaderBodyReply(absl::string_view reply) {
+ // Output formatting as header/body chunk as required by LSP spec to stdout.
+ std::cout << "Content-Length: " << reply.size() << "\r\n\r\n";
+ std::cout << reply << std::flush;
}
int main(int argc, char *argv[]) {
verible::InitCommandLine(argv[0], &argc, &argv);
+ std::cerr << "Verible Alpha Language Server "
+ << verilog::VerilogLanguageServer::GetVersionNumber() << std::endl;
+
#ifdef _WIN32
+ // Windows messes with newlines by default. Fix this here.
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
#endif
- std::cerr << "Verible Alpha Language Server " << GetVersionNumber()
- << std::endl;
-
// Input and output is stdin and stdout
- static constexpr int in_fd = 0; // STDIN_FILENO
- JsonRpcDispatcher::WriteFun write_fun = [](absl::string_view reply) {
- // Output formatting as header/body chunk as required by LSP spec.
- std::cout << "Content-Length: " << reply.size() << "\r\n\r\n";
- std::cout << reply << std::flush;
- };
+ constexpr int kInputFD = 0; // STDIN_FILENO, but Win does not have that macro
- // Stream splitter splits the input stream into messages (header/body).
- MessageStreamSplitter stream_splitter;
- JsonRpcDispatcher dispatcher(write_fun);
+ verilog::VerilogLanguageServer server(FormatHeaderBodyReply);
- // All bodies the stream splitter extracts are pushed to the json dispatcher
- stream_splitter.SetMessageProcessor(
- [&dispatcher](absl::string_view /*header*/, absl::string_view body) {
- return dispatcher.DispatchMessage(body);
- });
-
- // The buffer collection keeps track of all the buffers opened in the editor.
- // It registers callbacks to receive the relevant events on the dispatcher.
- BufferCollection buffers(&dispatcher);
-
- // The parsed buffers convert the raw text into the SystemVerilog parsed
- // representation, basis for all high-level features we provide from it.
- // Subscribe them to text edit updates to trigger parse.
- verilog::BufferTrackerContainer parsed_buffers;
- buffers.SetChangeListener(parsed_buffers.GetSubscriptionCallback());
-
- // Whenever there is a new parse result ready, use that as an opportunity
- // to send diagnostics to the client.
- parsed_buffers.SetChangeListener(
- [&dispatcher](const std::string &uri,
- const verilog::BufferTracker &buffer_tracker) {
- SendDiagnostics(uri, buffer_tracker, &dispatcher);
- });
-
- // -- Register JSON RPC callbacks
-
- // Exchange of capabilities.
- dispatcher.AddRequestHandler("initialize", InitializeServer);
-
- dispatcher.AddRequestHandler( // Provide diagnostics on request
- "textDocument/diagnostic",
- [&parsed_buffers](const verible::lsp::DocumentDiagnosticParams &p) {
- return verilog::GenerateDiagnosticReport(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
-
- dispatcher.AddRequestHandler( // Provide autofixes
- "textDocument/codeAction",
- [&parsed_buffers](const verible::lsp::CodeActionParams &p) {
- return verilog::GenerateLinterCodeActions(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
-
- dispatcher.AddRequestHandler( // Provide document outline/index
- "textDocument/documentSymbol",
- [&parsed_buffers](const verible::lsp::DocumentSymbolParams &p) {
- return verilog::CreateDocumentSymbolOutline(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
-
- dispatcher.AddRequestHandler( // Highlight related symbols under cursor
- "textDocument/documentHighlight",
- [&parsed_buffers](const verible::lsp::DocumentHighlightParams &p) {
- return verilog::CreateHighlightRanges(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
-
- dispatcher.AddRequestHandler( // format range of file
- "textDocument/rangeFormatting",
- [&parsed_buffers](const verible::lsp::DocumentFormattingParams &p) {
- return verilog::FormatRange(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
- dispatcher.AddRequestHandler( // format entire file
- "textDocument/formatting",
- [&parsed_buffers](const verible::lsp::DocumentFormattingParams &p) {
- return verilog::FormatRange(
- parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
- });
-
- // The client sends a request to shut down. Use that to exit our loop.
- bool shutdown_requested = false;
- dispatcher.AddRequestHandler("shutdown",
- [&shutdown_requested](const nlohmann::json &) {
- shutdown_requested = true;
- return nullptr;
- });
-
- absl::Status status = absl::OkStatus();
- while (status.ok() && !shutdown_requested) {
- status = stream_splitter.PullFrom([](char *buf, int size) -> int { //
- return read(in_fd, buf, size);
- });
- }
+ absl::Status status = server.Run([](char *buf, int size) -> int { //
+ return read(kInputFD, buf, size);
+ });
std::cerr << status.message() << std::endl;
- if (shutdown_requested) {
- std::cerr << "Shutting down due to shutdown request." << std::endl;
- }
-
- std::cerr << "Statistics" << std::endl;
- std::cerr << "Largest message seen: "
- << stream_splitter.StatLargestBodySeen() / 1024 << " kiB "
- << std::endl;
- for (const auto &stats : dispatcher.GetStatCounters()) {
- fprintf(stderr, "%30s %9d\n", stats.first.c_str(), stats.second);
- }
+ server.PrintStatistics();
}