[
  {
    "path": ".github/workflows/ci.yml",
    "content": "on:\n    push:\n    pull_request:\n    workflow_dispatch:\n    schedule:\n        - cron:  '0 0 * * 0'\n\nname: CI\n\njobs:\n    test:\n        name: Test Suite\n        runs-on: ubuntu-22.04\n        steps:\n            - name: Checkout sources\n              uses: actions/checkout@v6\n              with:\n                  submodules: true\n\n            - name: Install stable toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  profile: minimal\n                  toolchain: 1.91.1\n                  override: true\n\n            - name: cache cargo dirs\n              uses: actions/cache@v4\n              with:\n                  path: |\n                      ~/.cargo/registry\n                      ~/.cargo/git\n                      target\n                  key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}\n\n            - name: Install Deps\n              run: |\n                  wget 'https://github.com/chipsalliance/verible/releases/download/v0.0-3607-g46de0f64/verible-v0.0-3607-g46de0f64-linux-static-x86_64.tar.gz' -O verible.tar.gz\n                  tar -xf verible.tar.gz\n                  sudo cp verible-v0.0-3607-g46de0f64/bin/* /usr/bin\n                  sudo apt update\n                  sudo apt-get install -y verilator perl\n\n            - name: Run cargo test\n              uses: actions-rs/cargo@v1\n              with:\n                  command: test\n                  args: --all-features\n            #todo: vscode extensions tests\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: \"24\"\n            - name: build extension\n              working-directory: extensions/vscode\n              run: |\n                  npm install\n                  npm install -g @vscode/vsce\n                  vsce package -o veridian.vsix\n\n    lints:\n        name: Lints\n        runs-on: ubuntu-22.04\n        steps:\n            - name: Checkout sources\n              uses: actions/checkout@v6\n              with:\n                  submodules: true\n\n            - name: Install stable toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  profile: minimal\n                  toolchain: 1.91.1\n                  override: true\n                  components: rustfmt, clippy\n\n            - name: cache cargo dirs\n              uses: actions/cache@v4\n              with:\n                  path: |\n                      ~/.cargo/registry\n                      ~/.cargo/git\n                      target\n                  key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}\n\n            - name: Run cargo fmt\n              uses: actions-rs/cargo@v1\n              with:\n                  command: fmt\n                  args: --all -- --check\n            - uses: actions-rs/clippy-check@v1\n              with:\n                  token: ${{ secrets.GITHUB_TOKEN }}\n                  args: --all-features -- -D warnings\n\n    build_ubuntu:\n        name: Build Ubuntu\n        runs-on: ubuntu-22.04\n        if: ${{ github.ref == 'refs/heads/master' && ( github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' ) }}\n        steps:\n            - name: Checkout sources\n              uses: actions/checkout@v6\n\n            - name: Install stable toolchain\n              uses: actions-rs/toolchain@v1\n              with:\n                  profile: minimal\n                  toolchain: 1.91.1\n                  override: true\n\n            - name: cache cargo dirs\n              uses: actions/cache@v4\n              with:\n                  path: |\n                      ~/.cargo/registry\n                      ~/.cargo/git\n                      target\n                  key: ${{ runner.os }}-release-cargo-${{ hashFiles('**/Cargo.lock') }}\n\n            - name: Run cargo build\n              uses: actions-rs/cargo@v1\n              with:\n                  command: build\n                  args: --all-features --release\n\n            - name: Create archive\n              run: |\n                  strip target/release/veridian\n                  cp target/release/veridian .\n                  tar -czvf veridian-ubuntu-22.04.tar.gz veridian\n\n            - uses: actions/upload-artifact@v4\n              with:\n                  name: veridian-ubuntu-22.04.tar.gz\n                  path: veridian-ubuntu-22.04.tar.gz\n                  if-no-files-found: error\n\n    build_vscode:\n        name: Build vscode extension\n        runs-on: ubuntu-latest\n        if: ${{ ( github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' ) }}\n        steps:\n            - uses: actions/checkout@v6\n            - uses: actions/setup-node@v6\n              with:\n                  node-version: \"24\"\n            - name: build extension\n              working-directory: extensions/vscode\n              run: |\n                  npm install\n                  npm install -g @vscode/vsce\n                  vsce package -o veridian.vsix\n\n            - uses: actions/upload-artifact@v4\n              with:\n                  name: veridian.vsix\n                  path: extensions/vscode/veridian.vsix\n                  if-no-files-found: error\n\n    publish:\n        name: Create Release\n        needs: [build_ubuntu, build_vscode]\n        runs-on: ubuntu-latest\n        steps:\n            - uses: actions/download-artifact@v4\n              with:\n                  name: veridian-ubuntu-22.04.tar.gz\n            - uses: actions/download-artifact@v4\n              with:\n                  name: veridian.vsix\n            - uses: marvinpinto/action-automatic-releases@latest\n              with:\n                  repo_token: ${{ secrets.GITHUB_TOKEN }}\n                  automatic_release_tag: nightly\n                  prerelease: true\n                  title: nightly\n                  files: |\n                      veridian-ubuntu-22.04.tar.gz\n                      veridian.vsix\n"
  },
  {
    "path": ".gitignore",
    "content": "# Generated by Cargo\n# will have compiled files and executables\ndebug/\ntarget/\n\n# These are backup files generated by rustfmt\n**/*.rs.bk\n\ntests_rtl\nlog_files\ntest.txt\n\n.vscode/\nveridian-slang/slang_wrapper/slang/\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"veridian\"\nversion = \"0.1.0\"\nauthors = [\"Vivek Malneedi <vivekmalneedi@gmail.com>\"]\nedition = \"2018\"\n\n[features]\nslang = [\"veridian_slang\"]\n\n[dependencies]\nsv-parser = \"0.8.2\"\nlog = \"0.4.19\"\ntower-lsp = \"0.20.0\"\nflexi_logger = \"0.29.8\"\nropey = \"1.6.0\"\ntokio = { version = \"1.29.1\", features = [\"macros\", \"io-std\", \"rt-multi-thread\"] }\npath-clean = \"1.0.1\"\npathdiff = \"0.2.1\"\nwalkdir = \"2.3.3\"\nserde_yaml = \"0.9.25\"\nanyhow = \"1.0.72\"\nserde = \"1.0.179\"\nwhich = \"7.0.1\"\nregex = \"1.9.1\"\nstructopt = \"0.3.26\"\nstrum = \"0.26.1\"\nstrum_macros = \"0.26.1\"\n\n[dev-dependencies]\ntempdir = \"0.3.7\"\n\n[dependencies.veridian_slang]\noptional = true\npath = \"veridian-slang\"\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Vivek Malneedi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# veridian\n\n![build](https://github.com/vivekmalneedi/veridian/workflows/CI/badge.svg)\n![GitHub](https://img.shields.io/github/license/vivekmalneedi/veridian)\n\nA SystemVerilog Language Server\\\n<a href=\"https://asciinema.org/a/374859\" target=\"_blank\"><img src=\"https://asciinema.org/a/374859.svg\" width=\"500\"/></a>\n\n## Installation\n\n### Pre-Installation\n\n- It is recommended to install the [verible](https://github.com/google/verible) tools for\n  - formatting support with `verible-verilog-format`\n  - syntax checking support with `verible-verilog-syntax`\n- It is recommended to install [verilator](https://www.veripool.org/verilator/) for additional linting\n\n### Install from Release\n\n- Download the latest release for your OS from the [releases page](https://github.com/vivekmalneedi/veridian/releases)\n  - The nightly release contains the last successful build, and is not guaranteed to be stable\n  - The ubuntu build also includes [slang](https://github.com/MikePopoloski/slang) for linting\n\n### Install from Source\n\n- Build dependencies: Rust toolchain (Install through system package manager or through [rustup](https://rustup.rs/]))\n- optional: C++17 compatible compiler (for linting with slang)\n\n```bash\n# install with slang feature, if C++17 compiler is available\ncargo install --git https://github.com/vivekmalneedi/veridian.git --all-features\n# install if C++17 compiler is not available\ncargo install --git https://github.com/vivekmalneedi/veridian.git\n```\n\n## Usage\n\n### [neovim](https://github.com/neovim/nvim-lspconfig)\n```lua\nlocal lspconfutil = require 'lspconfig/util'\nlocal root_pattern = lspconfutil.root_pattern(\"veridian.yml\", \".git\")\nrequire('lspconfig').veridian.setup {\n    cmd = { 'veridian' },\n    root_dir = function(fname)\n        local filename = lspconfutil.path.is_absolute(fname) and fname\n        or lspconfutil.path.join(vim.loop.cwd(), fname)\n        return root_pattern(filename) or lspconfutil.path.dirname(filename)\n    end;\n}\n````\n\n### [vscode](https://github.com/vivekmalneedi/veridian/tree/master/extensions/vscode)\n\n- download veridian.vsix from the latest release\n- install the extension using one of the two following methods\n  - In the extensions tab, click on the 3 dots, then click `Install from VSIX` and choose `veridian.vsix`\n  - Run `code --install-extension veridian.vsix`\n\n### [coc.nvim](https://github.com/neoclide/coc.nvim)\n\nIn `coc-settings.json`:\n\n```json\n{\n  \"languageserver\": {\n    \"veridian\": {\n      \"command\": \"veridian\",\n      \"filetypes\": [\"systemverilog\", \"verilog\"]\n    }\n}\n\n```\n\n### Emacs\n\n- Install the [`verilog-ext`](https://github.com/gmlarumbe/verilog-ext/) package\n- Copy the following snippet into your init file:\n\n```elisp\n(require 'verilog-ext)\n(verilog-ext-mode-setup)\n(verilog-ext-eglot-set-server 've-veridian) ;`eglot' config\n(verilog-ext-lsp-set-server 've-veridian)   ; `lsp' config\n```\n\nThe [full list](https://github.com/vivekmalneedi/veridian/wiki/Usage-Instructions-for-various-LSP-Clients) is on the wiki\n\n## Configuration\n\n- Specify source directories and include directories using a yaml project config\n- All settings have defaults so your config file should only specify custom values\n\nIn `veridian.yml`:\n\n```yaml\n# list of directories with header files\ninclude_dirs:\n  - inc1\n  - inc2\n# list of directories to recursively search for SystemVerilog/Verilog sources\nsource_dirs:\n  - src\n  - src2\n# if true, recursively search the working directory for files to run diagnostics on\n# default: true\nauto_search_workdir: true|false,\n# verible tool configuration\nverible:\n  # verible-verilog-syntax configuration\n  syntax:\n    # default: true if in path\n    enabled: true|false,\n    path: \"verible-verilog-syntax\"\n    # default: none\n    args:\n      - arg1\n      - arg2\n  # verible-verilog-format configuration\n  format:\n    # default: true if in path\n    enabled: true|false,\n    path: \"verible-verilog-format\"\n    # default: none\n    args:\n      - arg1\n      - arg2\nverilator:\n  # verilator configuration\n  syntax:\n    # default: true if in path\n    enabled: true|false,\n    path: \"verilator\"\n    # default: specified below\n    args:\n      - --lint-only\n      - --sv\n      - -Wall\n# set log level\n# default: Info\nlog_level: Error|Warn|Info|Debug|Trace\n```\n\n## LSP Support\n\nSee the [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/specification-current/) for more details\n\n- diagnostics (using [slang](https://github.com/MikePopoloski/slang) or [verible](https://github.com/google/verible))\n- completion\n  - identifier completion\n  - dot completion\n  - keywords & snippets\n  - system task/function and compiler directives\n- hover (documentation)\n- definition\n- documentSymbol\n- documentHighlight\n- formatting (using [verible](https://github.com/google/verible))\n- rangeFormatting (using [verible](https://github.com/google/verible))\n\n## Alternatives\nThe Verible project is working on a language server for SystemVerilog, check it out [here](https://github.com/chipsalliance/verible/tree/master/verilog/tools/ls)\n"
  },
  {
    "path": "extensions/vscode/.eslintignore",
    "content": "node_modules/**\r\nout/**\r\n"
  },
  {
    "path": "extensions/vscode/.eslintrc.js",
    "content": "/**@type {import('eslint').Linter.Config} */\n// eslint-disable-next-line no-undef\nmodule.exports = {\n\troot: true,\n\tparser: '@typescript-eslint/parser',\n\tplugins: [\n\t\t'@typescript-eslint',\n\t],\n\textends: [\n\t\t'eslint:recommended',\n\t\t'plugin:@typescript-eslint/recommended',\n\t],\n\trules: {\n\t\t'semi': [2, \"always\"],\n\t\t'@typescript-eslint/no-unused-vars': 0,\n\t\t'@typescript-eslint/no-explicit-any': 0,\n\t\t'@typescript-eslint/explicit-module-boundary-types': 0,\n\t\t'@typescript-eslint/no-non-null-assertion': 0,\n\t}\n};"
  },
  {
    "path": "extensions/vscode/.eslintrc.json",
    "content": "{\r\n\t\"parser\": \"@typescript-eslint/parser\",\r\n\t\"parserOptions\": {\r\n\t\t\"ecmaVersion\": 6,\r\n\t\t\"sourceType\": \"module\"\r\n\t},\r\n\t\"env\": {\r\n\t\t\"node\": true\r\n\t},\r\n\t\"rules\": {\r\n\t\t\"semi\": \"error\",\r\n\t\t\"no-extra-semi\": \"warn\",\r\n\t\t\"curly\": \"warn\",\r\n\t\t\"quotes\": [\"error\", \"single\", { \"allowTemplateLiterals\": true } ],\r\n\t\t\"eqeqeq\": \"error\",\r\n\t\t\"indent\": [\"warn\", \"tab\", { \"SwitchCase\": 1 } ]\r\n\t}\r\n}"
  },
  {
    "path": "extensions/vscode/.gitignore",
    "content": "out\nnode_modules\n.vscode-test\n*.vsix\n"
  },
  {
    "path": "extensions/vscode/.vscodeignore",
    "content": ".vscode/**\r\n**/*.ts\r\n**/*.map\r\n.gitignore\r\n**/tsconfig.json\r\n**/tsconfig.base.json\r\ncontributing.md\r\n.travis.yml\r\n"
  },
  {
    "path": "extensions/vscode/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Vivek Malneedi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "extensions/vscode/README.md",
    "content": "# veridian\n\na vscode client extension for the veridian language server.\n\n- veridian must be installed seperately, see https://github.com/vivekmalneedi/veridian for details\n- provides syntax highlighting, the grammar for which is borrowed from https://github.com/TheClams/SystemVerilog and is under the Apache 2.0 License\n"
  },
  {
    "path": "extensions/vscode/package.json",
    "content": "{\n    \"name\": \"veridian\",\n    \"description\": \"A client for the Veridian Language Server for SystemVerilog/Verilog\",\n    \"author\": \"Vivek Malneedi\",\n    \"publisher\": \"vivekmalneedi\",\n    \"license\": \"MIT\",\n    \"version\": \"0.1.0\",\n    \"categories\": [\n        \"Programming Languages\",\n        \"Snippets\",\n        \"Linters\"\n    ],\n    \"keywords\": [\n        \"SystemVerilog\",\n        \"Verilog\"\n    ],\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/vivekmalneedi/veridian\"\n    },\n    \"activationEvents\": [\n        \"onLanguage:systemverilog\",\n        \"onLanguage:verilog\"\n    ],\n    \"main\": \"./out/extension\",\n    \"scripts\": {\n        \"vscode:prepublish\": \"npm run compile\",\n        \"compile\": \"tsc -b\",\n        \"watch\": \"tsc -b -w\"\n    },\n    \"contributes\": {\n        \"languages\": [\n            {\n                \"id\": \"systemverilog\",\n                \"extensions\": [\n                    \".sv\",\n                    \".svh\",\n                    \".v\",\n                    \".vh\",\n                    \".verilog\"\n                ],\n                \"aliases\": [\n                    \"SystemVerilog\",\n                    \"verilog\",\n                    \"Verilog\"\n                ]\n            }\n        ],\n        \"grammars\": [\n            {\n                \"language\": \"systemverilog\",\n                \"scopeName\": \"source.systemverilog\",\n                \"path\": \"./syntaxes/systemverilog.tmLanguage.json\"\n            }\n        ],\n        \"configuration\": {\n            \"type\": \"object\",\n            \"title\": \"veridian\",\n            \"properties\": {\n                \"veridian.serverPath\": {\n                    \"scope\": \"window\",\n                    \"type\": \"string\",\n                    \"default\": \"veridian\",\n                    \"description\": \"path of the veridian binary\"\n                },\n                \"veridian.trace.server\": {\n                    \"scope\": \"window\",\n                    \"type\": \"string\",\n                    \"enum\": [\n                        \"off\",\n                        \"messages\",\n                        \"verbose\"\n                    ],\n                    \"default\": \"off\",\n                    \"description\": \"Traces the communication between VS Code and the language server.\"\n                }\n            }\n        }\n    },\n    \"engines\": {\n\t\t\"vscode\": \"^1.100.0\"\n\t},\n    \"dependencies\": {\n\t\t\"glob\": \"^11.0.0\",\n\t\t\"vscode-languageclient\": \"^9.0.1\"\n\t},\n    \"devDependencies\": {\n\t\t\"@eslint/js\": \"^9.13.0\",\n\t\t\"@stylistic/eslint-plugin\": \"^2.9.0\",\n\t\t\"@types/mocha\": \"^10.0.6\",\n\t\t\"@types/node\": \"^22\",\n\t\t\"eslint\": \"^9.13.0\",\n\t\t\"mocha\": \"^10.3.0\",\n\t\t\"typescript\": \"^5.9.2\",\n\t\t\"typescript-eslint\": \"^8.39.0\",\n        \"@types/vscode\": \"^1.100.0\"\n\t}\n}\n"
  },
  {
    "path": "extensions/vscode/src/extension.ts",
    "content": "/* --------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n * ------------------------------------------------------------------------------------------ */\n\nimport { workspace, ExtensionContext } from \"vscode\";\n\nimport {\n  LanguageClient,\n  LanguageClientOptions,\n  ServerOptions,\n  Executable,\n} from \"vscode-languageclient/node\";\n\nlet client: LanguageClient;\nconst workSpaceFolder = workspace.workspaceFolders?.[0];\nlet cwd: string = workSpaceFolder.uri.fsPath;\nconst serverPath: string = workspace.getConfiguration().get(\"veridian.serverPath\");\n\nexport function activate(context: ExtensionContext) {\n  const run: Executable = {\n    command: serverPath,\n    // options: { cwd },\n  };\n\n  // If the extension is launched in debug mode then the debug server options are used\n  // Otherwise the run options are used\n  let serverOptions: ServerOptions = {\n    run,\n    debug: run,\n  };\n\n  // Options to control the language client\n  let clientOptions: LanguageClientOptions = {\n    // Register the server for plain text documents\n    documentSelector: [{ scheme: \"file\", language: \"systemverilog\" }],\n  };\n\n  // Create the language client and start the client.\n  client = new LanguageClient(\n    \"veridian\",\n    \"veridian\",\n    serverOptions,\n    clientOptions\n  );\n\n  // Start the client. This will also launch the server\n  client.start();\n}\n\nexport function deactivate(): Thenable<void> | undefined {\n  if (!client) {\n    return undefined;\n  }\n  return client.stop();\n}\n"
  },
  {
    "path": "extensions/vscode/syntaxes/systemverilog.tmLanguage.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json\",\n  \"fileTypes\": [\n    \"sv\",\n    \"SV\",\n    \"v\",\n    \"V\",\n    \"svh\",\n    \"SVH\",\n    \"vh\",\n    \"VH\"\n  ],\n  \"hidden\": true,\n  \"foldingStartMarker\": \"(begin)\\\\s*(//.*)?$\",\n  \"foldingStopMarker\": \"^\\\\s*(begin)$\",\n  \"name\": \"systemverilog\",\n  \"patterns\": [\n    {\n      \"begin\": \"\\\\s*\\\\b(function|task)\\\\b(\\\\s+automatic)?\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      },\n      \"end\": \";\",\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*\\\\s+)?([a-zA-Z_][a-zA-Z0-9_:]*)\\\\s*(?=\\\\(|;)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.type.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"entity.name.function.systemverilog\"\n            }\n          }\n        },\n        {\n          \"include\": \"#port-dir\"\n        },\n        {\n          \"include\": \"#base-grammar\"\n        }\n      ],\n      \"name\": \"meta.function.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(task)\\\\s+(automatic)?\\\\s*(\\\\w+)\\\\s*;\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.function.systemverilog\"\n        }\n      },\n      \"name\": \"meta.task.simple.systemverilog\"\n    },\n    {\n      \"begin\": \"\\\\s*\\\\b(typedef\\\\s+(struct|enum|union)\\\\b)\\\\s*(packed)?\\\\s*([a-zA-Z_][a-zA-Z0-9_]*)?\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"storage.type.systemverilog\"\n        }\n      },\n      \"end\": \"(})\\\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*;\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.function.systemverilog\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"include\": \"#struct-anonymous\"\n        },\n        {\n          \"include\": \"#base-grammar\"\n        }\n      ],\n      \"name\": \"meta.typedef.struct.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(typedef\\\\s+class)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*;\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.declaration.systemverilog\"\n        }\n      },\n      \"name\": \"meta.typedef.class.systemverilog\"\n    },\n    {\n      \"begin\": \"\\\\s*\\\\b(typedef)\\\\b\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      },\n      \"end\": \"([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*(?=(\\\\[[a-zA-Z0-9_:\\\\$\\\\-\\\\+]*\\\\])?;)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"entity.name.function.systemverilog\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b([a-zA-Z_]\\\\w*)\\\\s*(#)\\\\(\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.type.userdefined.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"keyword.operator.param.systemverilog\"\n            }\n          },\n          \"name\": \"meta.typedef.class.systemverilog\"\n        },\n        {\n          \"include\": \"#base-grammar\"\n        },\n        {\n          \"include\": \"#module-binding\"\n        }\n      ],\n      \"name\": \"meta.typedef.simple.systemverilog\"\n    },\n    {\n      \"begin\": \"\\\\s*(module)\\\\s+\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.type.module.systemverilog\"\n        }\n      },\n      \"end\": \";\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"entity.name.function.systemverilog\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"include\": \"#port-dir\"\n        },\n        {\n          \"match\": \"\\\\s*(parameter)\",\n          \"name\": \"keyword.other.systemverilog\"\n        },\n        {\n          \"include\": \"#base-grammar\"\n        },\n        {\n          \"include\": \"#ifmodport\"\n        }\n      ],\n      \"name\": \"meta.module.systemverilog\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.function.systemverilog\"\n        }\n      },\n      \"match\": \"\\\\b(sequence)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\",\n      \"name\": \"meta.sequence.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\b(bind)\\\\s+([a-zA-Z_][a-zA-Z0-9_\\\\.]*)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      }\n    },\n    {\n      \"captures\": {\n        \"0\": {\n          \"name\": \"meta.section.begin.systemverilog\"\n        },\n        \"1\": {\n          \"name\": \"keyword.other.block.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.operator.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"entity.name.section.systemverilog\"\n        }\n      },\n      \"match\": \"\\\\s*(begin|fork)\\\\s*((:)\\\\s*([a-zA-Z_][a-zA-Z0-9_]*))\\\\b\",\n      \"name\": \"meta.definition.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\b(property)\\\\s+(\\\\w+)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.sva.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.sva.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\b(\\\\w+)\\\\s*(:)\\\\s*(assert)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"entity.name.sva.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.operator.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.sva.systemverilog\"\n        }\n      }\n    },\n    {\n      \"begin\": \"\\\\s*(//)\\\\s*(psl)\\\\s+((\\\\w+)\\\\s*(:))?\\\\s*(default|assert|assume)\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"meta.psl.systemverilog\"\n        },\n        \"1\": {\n          \"name\": \"comment.line.double-slash.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.psl.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"entity.psl.name.systemverilog\"\n        },\n        \"5\": {\n          \"name\": \"keyword.operator.systemverilog\"\n        },\n        \"6\": {\n          \"name\": \"keyword.psl.systemverilog\"\n        }\n      },\n      \"end\": \";\",\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(never|always|default|clock|within|rose|fell|stable|until|before|next|eventually|abort|posedge)\\\\b\",\n          \"name\": \"keyword.psl.systemverilog\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#functions\"\n        },\n        {\n          \"include\": \"#constants\"\n        }\n      ],\n      \"name\": \"meta.psl.systemverilog\"\n    },\n    {\n      \"begin\": \"\\\\s*(/\\\\*)\\\\s*(psl)\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"meta.psl.systemverilog\"\n        },\n        \"1\": {\n          \"name\": \"comment.block.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.psl.systemverilog\"\n        }\n      },\n      \"end\": \"(\\\\*/)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"comment.block.systemverilog\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"match\": \"^\\\\s*((\\\\w+)\\\\s*(:))?\\\\s*(default|assert|assume)\",\n          \"captures\": {\n            \"0\": {\n              \"name\": \"meta.psl.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"entity.psl.name.systemverilog\"\n            },\n            \"3\": {\n              \"name\": \"keyword.operator.systemverilog\"\n            },\n            \"4\": {\n              \"name\": \"keyword.psl.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\b(property)\\\\s+(\\\\w+)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"keyword.psl.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"entity.psl.name.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\b(never|always|default|clock|within|rose|fell|stable|until|before|next|eventually|abort|posedge|negedge)\\\\b\",\n          \"name\": \"keyword.psl.systemverilog\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#functions\"\n        },\n        {\n          \"include\": \"#constants\"\n        }\n      ],\n      \"name\": \"meta.psl.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(automatic|cell|config|deassign|defparam|design|disable|edge|endconfig|endgenerate|endspecify|endtable|event|generate|genvar|ifnone|incdir|instance|liblist|library|macromodule|negedge|noshowcancelled|posedge|pulsestyle_onevent|pulsestyle_ondetect|scalared|showcancelled|specify|specparam|table|use|vectored)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(initial|always|wait|force|release|assign|always_comb|always_ff|always_latch|forever|repeat|while|for|if|iff|else|case|casex|casez|default|endcase|return|break|continue|do|foreach|with|inside|dist|clocking|cover|coverpoint|property|bins|binsof|illegal_bins|ignore_bins|randcase|modport|matches|solve|static|assert|assume|before|expect|cross|ref|first_match|srandom|struct|packed|final|chandle|alias|tagged|extern|throughout|timeprecision|timeunit|priority|type|union|uwire|wait_order|triggered|randsequence|import|export|context|pure|intersect|wildcard|within|new|typedef|enum|this|super|begin|fork|forkjoin|unique|unique0|priority)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(end|endtask|endmodule|endfunction|endprimitive|endclass|endpackage|endsequence|endprogram|endclocking|endproperty|endgroup|endinterface|join|join_any|join_none)\\\\b(\\\\s*(:)\\\\s*(\\\\w+))?\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.operator.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"entity.label.systemverilog\"\n        }\n      },\n      \"name\": \"meta.object.end.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\b(std)\\\\b::\",\n      \"name\": \"support.class.systemverilog\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"constant.other.define.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.type.define.systemverilog\"\n        }\n      },\n      \"match\": \"^\\\\s*(`define)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\",\n      \"name\": \"meta.define.systemverilog\"\n    },\n    {\n      \"include\": \"#comments\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.type.class.systemverilog\"\n        }\n      },\n      \"match\": \"\\\\s*(primitive|package|constraint|interface|covergroup|program)\\\\s+\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"name\": \"meta.definition.systemverilog\"\n    },\n    {\n      \"captures\": {\n        \"2\": {\n          \"name\": \"entity.name.type.class.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      },\n      \"match\": \"(([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*(:))?\\\\s*(coverpoint|cross)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\",\n      \"name\": \"meta.definition.systemverilog\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.type.class.systemverilog\"\n        }\n      },\n      \"match\": \"\\\\b(virtual\\\\s+)?(class)\\\\s+\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"name\": \"meta.definition.class.systemverilog\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.other.inherited-class.systemverilog\"\n        }\n      },\n      \"match\": \"\\\\b(extends)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"name\": \"meta.definition.systemverilog\"\n    },\n    {\n      \"include\": \"#all-types\"\n    },\n    {\n      \"include\": \"#operators\"\n    },\n    {\n      \"include\": \"#port-dir\"\n    },\n    {\n      \"match\": \"\\\\b(and|nand|nor|or|xor|xnor|buf|not|bufif[01]|notif[01]|r?[npc]mos|tran|r?tranif[01]|pullup|pulldown)\\\\b\",\n      \"name\": \"support.type.systemverilog\"\n    },\n    {\n      \"include\": \"#strings\"\n    },\n    {\n      \"match\": \"\\\\$\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"name\": \"support.function.systemverilog\"\n    },\n    {\n      \"match\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*)(')(?=\\\\()\",\n      \"name\": \"meta.cast.systemverilog\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"storage.type.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.operator.cast.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"^\\\\s*(localparam|parameter)\\\\s+([A-Z_][A-Z0-9_]*)\\\\b\\\\s*(?=(=))\",\n      \"name\": \"meta.param.systemverilog\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"constant.other.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"^\\\\s*(localparam|parameter)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\\\\s*(?=(=))\",\n      \"name\": \"meta.param.systemverilog\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"^\\\\s*(local\\\\s+|protected\\\\s+|localparam\\\\s+|parameter\\\\s+)?(const\\\\s+|virtual\\\\s+)?(rand\\\\s+|randc\\\\s+)?(([a-zA-Z_][a-zA-Z0-9_]*)(::))?([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\\\\s*(?=(#\\\\s*\\\\([\\\\w,]+\\\\)\\\\s*)?([a-zA-Z][a-zA-Z0-9_\\\\s\\\\[\\\\]']*)(;|,|=|'\\\\{))\",\n      \"name\": \"meta.userdefined.systemverilog\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.other.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"storage.type.rand.systemverilog\"\n        },\n        \"5\": {\n          \"name\": \"support.type.scope.systemverilog\"\n        },\n        \"6\": {\n          \"name\": \"keyword.operator.scope.systemverilog\"\n        },\n        \"7\": {\n          \"name\": \"storage.type.userdefined.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(option)\\\\.\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.cover.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(local|const|protected|virtual|localparam|parameter)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.systemverilog\"\n        }\n      }\n    },\n    {\n      \"match\": \"\\\\s*\\\\b(rand|randc)\\\\b\",\n      \"name\": \"storage.type.rand.systemverilog\"\n    },\n    {\n      \"begin\": \"^(\\\\s*(bind)\\\\s+([a-zA-Z_][\\\\w\\\\.]*))?\\\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*(?=#[^#])\",\n      \"beginCaptures\": {\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"storage.module.systemverilog\"\n        }\n      },\n      \"end\": \"(?=;|=|:)\",\n      \"patterns\": [\n        {\n          \"include\": \"#module-binding\"\n        },\n        {\n          \"include\": \"#module-param\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"match\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b(?=\\\\s*(\\\\(|$))\",\n          \"name\": \"entity.name.type.module.systemverilog\"\n        }\n      ],\n      \"name\": \"meta.module.inst.param.systemverilog\"\n    },\n    {\n      \"begin\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\s+(?!intersect|and|or|throughout|within)([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*(\\\\[(\\\\d+)(\\\\:(\\\\d+))?\\\\])?\\\\s*(\\\\(|$)\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"storage.module.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.type.module.systemverilog\"\n        },\n        \"4\": {\n          \"name\": \"constant.numeric.systemverilog\"\n        },\n        \"6\": {\n          \"name\": \"constant.numeric.systemverilog\"\n        }\n      },\n      \"end\": \";\",\n      \"patterns\": [\n        {\n          \"include\": \"#module-binding\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#constants\"\n        }\n      ],\n      \"name\": \"meta.module.inst.systemverilog\"\n    },\n    {\n      \"name\": \"meta.struct.assign.systemverilog\",\n      \"begin\": \"\\\\b\\\\s+(<?=)\\\\s*(\\\\'{)\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        },\n        \"3\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        }\n      },\n      \"end\": \";\",\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(\\\\w+)\\\\s*(:)(?!:)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"support.function.field.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"keyword.operator.other.systemverilog\"\n            }\n          }\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#storage-scope-systemverilog\"\n        }\n      ]\n    },\n    {\n      \"include\": \"#storage-scope-systemverilog\"\n    },\n    {\n      \"include\": \"#functions\"\n    },\n    {\n      \"include\": \"#constants\"\n    }\n  ],\n  \"repository\": {\n    \"functions\": {\n      \"match\": \"\\\\b(\\\\w+)(?=\\\\s*\\\\()\",\n      \"name\": \"support.function.generic.systemverilog\"\n    },\n    \"all-types\": {\n      \"patterns\": [\n        {\n          \"include\": \"#storage-type-systemverilog\"\n        },\n        {\n          \"include\": \"#storage-modifier-systemverilog\"\n        }\n      ]\n    },\n    \"constants\": {\n      \"patterns\": [\n        {\n          \"match\": \"(\\\\b\\\\d+)?'(s?[bB]\\\\s*[0-1xXzZ?][0-1_xXzZ?]*|s?[oO]\\\\s*[0-7xXzZ?][0-7_xXzZ?]*|s?[dD]\\\\s*[0-9xXzZ?][0-9_xXzZ?]*|s?[hH]\\\\s*[0-9a-fA-FxXzZ?][0-9a-fA-F_xXzZ?]*)((e|E)(\\\\+|-)?[0-9]+)?(?!'|\\\\w)\",\n          \"name\": \"constant.numeric.systemverilog\"\n        },\n        {\n          \"match\": \"'[01xXzZ]\",\n          \"name\": \"constant.numeric.bit.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b((\\\\d[\\\\d_]*)(e|E)(\\\\+|-)?[0-9]+)\\\\b\",\n          \"name\": \"constant.numeric.exp.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b(\\\\d[\\\\d_]*)\\\\b\",\n          \"name\": \"constant.numeric.decimal.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b(\\\\d+(fs|ps|ns|us|ms|s)?)\\\\b\",\n          \"name\": \"constant.numeric.time.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b([A-Z][A-Z0-9_]*)\\\\b\",\n          \"name\": \"constant.other.net.systemverilog\"\n        },\n        {\n          \"match\": \"(`ifdef|`ifndef|`default_nettype)\\\\s+(\\\\w+)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"constant.other.preprocessor.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"support.variable.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"`(celldefine|else|elsif|endcelldefine|endif|include|line|nounconnected_drive|resetall|timescale|unconnected_drive|undef|begin_\\\\w+|end_\\\\w+|remove_\\\\w+|restore_\\\\w+)\\\\b\",\n          \"name\": \"constant.other.preprocessor.systemverilog\"\n        },\n        {\n          \"match\": \"`\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n          \"name\": \"constant.other.define.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b(null)\\\\b\",\n          \"name\": \"support.constant.systemverilog\"\n        }\n      ]\n    },\n    \"operators\": {\n      \"patterns\": [\n        {\n          \"match\": \"(=|==|===|!=|!==|<=|>=|<|>)\",\n          \"name\": \"keyword.operator.comparison.systemverilog\"\n        },\n        {\n          \"match\": \"(\\\\-|\\\\+|\\\\*|\\\\/|%)\",\n          \"name\": \"keyword.operator.arithmetic.systemverilog\"\n        },\n        {\n          \"match\": \"(!|&&|\\\\|\\\\||\\\\bor\\\\b)\",\n          \"name\": \"keyword.operator.logical.systemverilog\"\n        },\n        {\n          \"match\": \"(&|\\\\||\\\\^|~|{|'{|}|<<|>>|\\\\?|:)\",\n          \"name\": \"keyword.operator.bitwise.systemverilog\"\n        },\n        {\n          \"match\": \"(#|@)\",\n          \"name\": \"keyword.operator.other.systemverilog\"\n        }\n      ]\n    },\n    \"comments\": {\n      \"patterns\": [\n        {\n          \"begin\": \"/\\\\*\",\n          \"captures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.systemverilog\"\n            }\n          },\n          \"end\": \"\\\\*/\",\n          \"name\": \"comment.block.systemverilog\"\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.comment.systemverilog\"\n            }\n          },\n          \"match\": \"(//).*$\\\\n?\",\n          \"name\": \"comment.line.double-slash.systemverilog\"\n        }\n      ]\n    },\n    \"port-dir\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\s*\\\\b(output|input|inout|ref)\\\\s+(([a-zA-Z_][a-zA-Z0-9_]*)(::))?([a-zA-Z_][a-zA-Z0-9_]*)?\\\\s+(?=\\\\[[a-zA-Z0-9_\\\\-\\\\+]*:[a-zA-Z0-9_\\\\-\\\\+]*\\\\]\\\\s+[a-zA-Z_][a-zA-Z0-9_\\\\s]*)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"support.type.systemverilog\"\n            },\n            \"3\": {\n              \"name\": \"support.type.scope.systemverilog\"\n            },\n            \"4\": {\n              \"name\": \"keyword.operator.scope.systemverilog\"\n            },\n            \"5\": {\n              \"name\": \"storage.type.interface.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\s*\\\\b(output|input|inout|ref)\\\\s+(([a-zA-Z_][a-zA-Z0-9_]*)(::))?([a-zA-Z_][a-zA-Z0-9_]*)?\\\\s+(?=[a-zA-Z_][a-zA-Z0-9_\\\\s]*)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"support.type.systemverilog\"\n            },\n            \"3\": {\n              \"name\": \"support.type.scope.systemverilog\"\n            },\n            \"4\": {\n              \"name\": \"keyword.operator.scope.systemverilog\"\n            },\n            \"5\": {\n              \"name\": \"storage.type.interface.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\s*\\\\b(output|input|inout|ref)\\\\b\",\n          \"name\": \"support.type.systemverilog\"\n        }\n      ]\n    },\n    \"base-grammar\": {\n      \"patterns\": [\n        {\n          \"include\": \"#all-types\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"match\": \"^\\\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\\\s+[a-zA-Z_][a-zA-Z0-9_,=\\\\s]*\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.type.interface.systemverilog\"\n            }\n          }\n        },\n        {\n          \"include\": \"#storage-scope-systemverilog\"\n        }\n      ]\n    },\n    \"storage-type-systemverilog\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\s*\\\\b(var|wire|tri|tri[01]|supply[01]|wand|triand|wor|trior|trireg|reg|integer|int|longint|shortint|logic|bit|byte|shortreal|string|time|realtime|real|process|void)\\\\b\",\n          \"name\": \"storage.type.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\s*\\\\b(uvm_transaction|uvm_component|uvm_monitor|uvm_driver|uvm_test|uvm_env|uvm_object|uvm_agent|uvm_sequence_base|uvm_sequence|uvm_sequence_item|uvm_sequence_state|uvm_sequencer|uvm_sequencer_base|uvm_component_registry|uvm_analysis_imp|uvm_analysis_port|uvm_analysis_export|uvm_config_db|uvm_active_passive_enum|uvm_phase|uvm_verbosity|uvm_tlm_analysis_fifo|uvm_tlm_fifo|uvm_report_server|uvm_objection|uvm_recorder|uvm_domain|uvm_reg_field|uvm_reg|uvm_reg_block|uvm_bitstream_t|uvm_radix_enum|uvm_printer|uvm_packer|uvm_comparer|uvm_scope_stack)\\\\b\",\n          \"name\": \"storage.type.uvm.systemverilog\"\n        }\n      ]\n    },\n    \"storage-scope-systemverilog\": {\n      \"match\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*)(::)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"support.type.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.operator.scope.systemverilog\"\n        }\n      },\n      \"name\": \"meta.scope.systemverilog\"\n    },\n    \"storage-modifier-systemverilog\": {\n      \"match\": \"\\\\b(signed|unsigned|small|medium|large|supply[01]|strong[01]|pull[01]|weak[01]|highz[01])\\\\b\",\n      \"name\": \"storage.modifier.systemverilog\"\n    },\n    \"ifmodport\": {\n      \"match\": \"\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\.([a-zA-Z_][a-zA-Z0-9_]*)\\\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"storage.type.interface.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"support.modport.systemverilog\"\n        }\n      }\n    },\n    \"strings\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\"\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.systemverilog\"\n            }\n          },\n          \"end\": \"\\\"\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.systemverilog\"\n            }\n          },\n          \"name\": \"string.quoted.double.systemverilog\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.systemverilog\"\n            },\n            {\n              \"match\": \"(?x)%\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(\\\\d+\\\\$)?                             # field (argument #)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[#0\\\\- +']*                           # flags\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[,;:_]?                              # separator character (AltiVec)\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t((-?\\\\d+)|\\\\*(-?\\\\d+\\\\$)?)?              # minimum field width\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(\\\\.((-?\\\\d+)|\\\\*(-?\\\\d+\\\\$)?)?)?         # precision\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t(hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t[bdiouxXhHDOUeEfFgGaACcSspnmt%]      # conversion type\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\",\n              \"name\": \"constant.other.placeholder.systemverilog\"\n            },\n            {\n              \"match\": \"%\",\n              \"name\": \"invalid.illegal.placeholder.systemverilog\"\n            }\n          ]\n        }\n      ]\n    },\n    \"module-binding\": {\n      \"begin\": \"\\\\.([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*\\\\(\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"support.function.port.systemverilog\"\n        }\n      },\n      \"end\": \"\\\\)\",\n      \"patterns\": [\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"match\": \"\\\\b([a-zA-Z_]\\\\w*)(::)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"support.type.scope.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"keyword.operator.scope.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\b([a-zA-Z_]\\\\w*)(')\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.type.interface.systemverilog\"\n            },\n            \"2\": {\n              \"name\": \"keyword.operator.cast.systemverilog\"\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\$\\\\b([a-zA-Z_][a-zA-Z0-9_]*)\\\\b\",\n          \"name\": \"support.function.systemverilog\"\n        },\n        {\n          \"match\": \"\\\\b(virtual)\\\\b\",\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      ],\n      \"match\": \"\\\\.([a-zA-Z_][a-zA-Z0-9_]*)\\\\s*\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"support.function.port.implicit.systemverilog\"\n        }\n      }\n    },\n    \"module-param\": {\n      \"name\": \"meta.module-param.systemverilog\",\n      \"begin\": \"(#)\\\\s*\\\\(\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.operator.param.systemverilog\"\n        }\n      },\n      \"end\": \"\\\\)\",\n      \"patterns\": [\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#operators\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#module-binding\"\n        },\n        {\n          \"match\": \"\\\\b(virtual)\\\\b\",\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      ]\n    },\n    \"struct-anonymous\": {\n      \"begin\": \"\\\\s*\\\\b(struct|union)\\\\s*(packed)?\\\\s*\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.control.systemverilog\"\n        },\n        \"2\": {\n          \"name\": \"keyword.control.systemverilog\"\n        }\n      },\n      \"end\": \"(})\\\\s*([a-zA-Z_]\\\\w*)\\\\s*;\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.operator.other.systemverilog\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"include\": \"#base-grammar\"\n        }\n      ],\n      \"name\": \"meta.struct.anonymous.systemverilog\"\n    }\n  },\n  \"scopeName\": \"source.systemverilog\",\n  \"uuid\": \"789be04c-8b74-352e-8f37-63d336001277\"\n}"
  },
  {
    "path": "extensions/vscode/tsconfig.json",
    "content": "{\r\n\t\"compilerOptions\": {\r\n\t\t\"module\": \"commonjs\",\r\n\t\t\"target\": \"es2019\",\r\n\t\t\"lib\": [\"ES2019\"],\r\n\t\t\"outDir\": \"out\",\r\n\t\t\"rootDir\": \"src\",\r\n\t\t\"sourceMap\": true\r\n\t},\r\n\t\"include\": [\"src\"],\r\n\t\"exclude\": [\"node_modules\", \".vscode-test\"]\r\n}\r\n"
  },
  {
    "path": "extensions/vscode/tsconfig.tsbuildinfo",
    "content": "{\"root\":[\"./src/extension.ts\"],\"version\":\"5.9.3\"}"
  },
  {
    "path": "rustfmt.toml",
    "content": "edition = \"2018\"\nmax_width = 100\n"
  },
  {
    "path": "src/completion/keyword.rs",
    "content": "use tower_lsp::lsp_types::*;\n\npub fn keyword_completions(keywords: &[(&str, &str)]) -> Vec<CompletionItem> {\n    let mut items: Vec<CompletionItem> = Vec::new();\n    for key in keywords {\n        if key.1.is_empty() {\n            items.push(CompletionItem {\n                label: key.0.to_string(),\n                kind: Some(CompletionItemKind::KEYWORD),\n                ..CompletionItem::default()\n            });\n        } else {\n            items.push(CompletionItem {\n                label: key.0.to_string(),\n                kind: Some(CompletionItemKind::KEYWORD),\n                insert_text: Some(key.1.to_string()),\n                insert_text_format: Some(InsertTextFormat::SNIPPET),\n                ..CompletionItem::default()\n            })\n        }\n    }\n    items\n}\n\npub fn other_completions(tasks: &[&str]) -> Vec<CompletionItem> {\n    tasks\n        .iter()\n        .map(|x| CompletionItem {\n            label: x.to_string(),\n            kind: Some(CompletionItemKind::FUNCTION),\n            ..CompletionItem::default()\n        })\n        .collect()\n}\n\npub const KEYWORDS: &[(&str, &str)] = &[\n    (\"accept_on\", \"\"),\n    (\"alias\", \"\"),\n    (\"always\", \"always @($1) begin\\nend\"),\n    (\"always_comb\", \"always_comb begin\\n\\t$1\\nend\"),\n    (\"always_ff\", \"always_ff @($1) begin\\nend\"),\n    (\"always_latch\", \"always_latch begin\\n\\t$1\\nend\"),\n    (\"and\", \"\"),\n    (\"assert\", \"\"),\n    (\"assign\", \"\"),\n    (\"assume\", \"\"),\n    (\"automatic\", \"\"),\n    (\"before\", \"\"),\n    (\"begin\", \"begin\\n\\t$1\\nend\"),\n    (\"bind\", \"\"),\n    (\"bins\", \"\"),\n    (\"binsof\", \"\"),\n    (\"bit\", \"\"),\n    (\"break\", \"\"),\n    (\"buf\", \"\"),\n    (\"bufif0\", \"\"),\n    (\"bufif1\", \"\"),\n    (\"byte\", \"\"),\n    (\"case\", \"case $1;\\nendcase\"),\n    (\"casex\", \"casex $1;\\nendcase\"),\n    (\"casez\", \"casez $1;\\nendcase\"),\n    (\"cell\", \"\"),\n    (\"chandle\", \"\"),\n    (\"checker\", \"checker $1;\\nendchecker\"),\n    (\"class\", \"class $1;\\nendclass\"),\n    (\"clocking\", \"clocking $1;\\nendclocking\"),\n    (\"cmos\", \"\"),\n    (\"config\", \"config $1;\\nendconfig\"),\n    (\"const\", \"\"),\n    (\"constraint\", \"\"),\n    (\"context\", \"\"),\n    (\"continue\", \"\"),\n    (\"cover\", \"\"),\n    (\"covergroup\", \"\"),\n    (\"coverpoint\", \"\"),\n    (\"cross\", \"\"),\n    (\"deassign\", \"\"),\n    (\"default\", \"\"),\n    (\"defparam\", \"\"),\n    (\"design\", \"\"),\n    (\"disable\", \"\"),\n    (\"dist\", \"\"),\n    (\"do\", \"\"),\n    (\"edge\", \"\"),\n    (\"else\", \"\"),\n    (\"end\", \"\"),\n    (\"endcase\", \"\"),\n    (\"endchecker\", \"\"),\n    (\"endclass\", \"\"),\n    (\"endclocking\", \"\"),\n    (\"endconfig\", \"\"),\n    (\"endfunction\", \"\"),\n    (\"endgenerate\", \"\"),\n    (\"endgroup\", \"\"),\n    (\"endinterface\", \"\"),\n    (\"endmodule\", \"\"),\n    (\"endpackage\", \"\"),\n    (\"endprimitive\", \"\"),\n    (\"endprogram\", \"\"),\n    (\"endproperty\", \"\"),\n    (\"endspecify\", \"\"),\n    (\"endsequence\", \"\"),\n    (\"endtable\", \"\"),\n    (\"endtask\", \"\"),\n    (\"enum\", \"\"),\n    (\"event\", \"\"),\n    (\"eventually\", \"\"),\n    (\"expect\", \"\"),\n    (\"export\", \"\"),\n    (\"extends\", \"\"),\n    (\"extern\", \"\"),\n    (\"final\", \"\"),\n    (\"first_match\", \"\"),\n    (\"for\", \"\"),\n    (\"force\", \"\"),\n    (\"foreach\", \"\"),\n    (\"forever\", \"\"),\n    (\"fork\", \"\"),\n    (\"forkjoin\", \"\"),\n    (\"function\", \"function $1;\\nendfunction\"),\n    (\"generate\", \"generate\\n\\t$1\\nendgenerate\"),\n    (\"genvar\", \"\"),\n    (\"global\", \"\"),\n    (\"highz0\", \"\"),\n    (\"highz1\", \"\"),\n    (\"if\", \"\"),\n    (\"iff\", \"\"),\n    (\"ifnone\", \"\"),\n    (\"ignore_bins\", \"\"),\n    (\"illegal_bins\", \"\"),\n    (\"implements\", \"\"),\n    (\"implies\", \"\"),\n    (\"import\", \"\"),\n    (\"incdir\", \"\"),\n    (\"include\", \"\"),\n    (\"initial\", \"\"),\n    (\"inout\", \"\"),\n    (\"input\", \"\"),\n    (\"inside\", \"\"),\n    (\"instance\", \"\"),\n    (\"int\", \"\"),\n    (\"integer\", \"\"),\n    (\"interconnect\", \"\"),\n    (\"interface\", \"interface $1;\\nendinterface\"),\n    (\"intersect\", \"\"),\n    (\"join\", \"\"),\n    (\"join_any\", \"\"),\n    (\"join_none\", \"\"),\n    (\"large\", \"\"),\n    (\"let\", \"\"),\n    (\"liblist\", \"\"),\n    (\"library\", \"\"),\n    (\"local\", \"\"),\n    (\"localparam\", \"\"),\n    (\"logic\", \"\"),\n    (\"longint\", \"\"),\n    (\"macromodule\", \"\"),\n    (\"matches\", \"\"),\n    (\"medium\", \"\"),\n    (\"modport\", \"\"),\n    (\"module\", \"module $1 ($2);\\nendmodule\"),\n    (\"nand\", \"\"),\n    (\"negedge\", \"\"),\n    (\"nettype\", \"\"),\n    (\"new\", \"\"),\n    (\"nexttime\", \"\"),\n    (\"nmos\", \"\"),\n    (\"nor\", \"\"),\n    (\"noshowcancelled\", \"\"),\n    (\"not\", \"\"),\n    (\"notif0\", \"\"),\n    (\"notif1\", \"\"),\n    (\"null\", \"\"),\n    (\"or\", \"\"),\n    (\"output\", \"\"),\n    (\"package\", \"package $1;\\nendpackage\"),\n    (\"packed\", \"\"),\n    (\"parameter\", \"\"),\n    (\"pmos\", \"\"),\n    (\"posedge\", \"\"),\n    (\"primitive\", \"primitive $1;\\nendprimitive\"),\n    (\"priority\", \"\"),\n    (\"program\", \"program $1;\\nendprogram\"),\n    (\"property\", \"property $1;\\nendproperty\"),\n    (\"protected\", \"\"),\n    (\"pull0\", \"\"),\n    (\"pull1\", \"\"),\n    (\"pulldown\", \"\"),\n    (\"pullup\", \"\"),\n    (\"pulsestyle_ondetect\", \"\"),\n    (\"pulsestyle_onevent\", \"\"),\n    (\"pure\", \"\"),\n    (\"rand\", \"\"),\n    (\"randc\", \"\"),\n    (\"randcase\", \"\"),\n    (\"randsequence\", \"\"),\n    (\"rcmos\", \"\"),\n    (\"real\", \"\"),\n    (\"realtime\", \"\"),\n    (\"ref\", \"\"),\n    (\"reg\", \"\"),\n    (\"reject_on\", \"\"),\n    (\"release\", \"\"),\n    (\"repeat\", \"\"),\n    (\"restrict\", \"\"),\n    (\"return\", \"\"),\n    (\"rnmos\", \"\"),\n    (\"rpmos\", \"\"),\n    (\"rtran\", \"\"),\n    (\"rtranif0\", \"\"),\n    (\"rtranif1\", \"\"),\n    (\"s_always\", \"\"),\n    (\"s_eventually\", \"\"),\n    (\"s_nexttime\", \"\"),\n    (\"s_until\", \"\"),\n    (\"s_until_with\", \"\"),\n    (\"scalared\", \"\"),\n    (\"sequence\", \"sequence $1;\\nendsequence\"),\n    (\"shortint\", \"\"),\n    (\"shortreal\", \"\"),\n    (\"showcancelled\", \"\"),\n    (\"signed\", \"\"),\n    (\"small\", \"\"),\n    (\"soft\", \"\"),\n    (\"solve\", \"\"),\n    (\"specify\", \"specify $1;\\nendspecify\"),\n    (\"specparam\", \"\"),\n    (\"static\", \"\"),\n    (\"string\", \"\"),\n    (\"strong\", \"\"),\n    (\"strong0\", \"\"),\n    (\"strong1\", \"\"),\n    (\"struct\", \"\"),\n    (\"super\", \"\"),\n    (\"supply0\", \"\"),\n    (\"supply1\", \"\"),\n    (\"sync_accept_on\", \"\"),\n    (\"sync_reject_on\", \"\"),\n    (\"table\", \"table $1;\\nendtable\"),\n    (\"tagged\", \"\"),\n    (\"task\", \"task $1;\\nendtask\"),\n    (\"this\", \"\"),\n    (\"throughout\", \"\"),\n    (\"time\", \"\"),\n    (\"timeprecision\", \"\"),\n    (\"timeunit\", \"\"),\n    (\"tran\", \"\"),\n    (\"tranif0\", \"\"),\n    (\"tranif1\", \"\"),\n    (\"tri\", \"\"),\n    (\"tri0\", \"\"),\n    (\"tri1\", \"\"),\n    (\"triand\", \"\"),\n    (\"trior\", \"\"),\n    (\"trireg\", \"\"),\n    (\"type\", \"\"),\n    (\"typedef\", \"\"),\n    (\"union\", \"\"),\n    (\"unique\", \"\"),\n    (\"unique0\", \"\"),\n    (\"unsigned\", \"\"),\n    (\"until\", \"\"),\n    (\"until_with\", \"\"),\n    (\"untyped\", \"\"),\n    (\"use\", \"\"),\n    (\"uwire\", \"\"),\n    (\"var\", \"\"),\n    (\"vectored\", \"\"),\n    (\"virtual\", \"\"),\n    (\"void\", \"\"),\n    (\"wait\", \"\"),\n    (\"wait_order\", \"\"),\n    (\"wand\", \"\"),\n    (\"weak\", \"\"),\n    (\"weak0\", \"\"),\n    (\"weak1\", \"\"),\n    (\"while\", \"\"),\n    (\"wildcard\", \"\"),\n    (\"wire\", \"\"),\n    (\"with\", \"\"),\n    (\"within\", \"\"),\n    (\"wor\", \"\"),\n    (\"xnor\", \"\"),\n    (\"xor\", \"\"),\n];\n\npub const SYS_TASKS: &[&str] = &[\n    \"finish\",\n    \"exit\",\n    \"fatal\",\n    \"warning\",\n    \"stop\",\n    \"error\",\n    \"info\",\n    \"realtime\",\n    \"time\",\n    \"asserton\",\n    \"assertkill\",\n    \"assertpasson\",\n    \"assertfailon\",\n    \"assertnonvacuouson\",\n    \"stime\",\n    \"printtimescale\",\n    \"timeformat\",\n    \"bitstoreal\",\n    \"bitstoshortreal\",\n    \"itor\",\n    \"signed\",\n    \"cast\",\n    \"realtobits\",\n    \"shortrealtobits\",\n    \"rtoi\",\n    \"unsigned\",\n    \"sampled\",\n    \"fell\",\n    \"changed\",\n    \"past_gclk\",\n    \"fell_gclk\",\n    \"changed_gclk\",\n    \"rising_gclk\",\n    \"steady_gclk\",\n    \"bits\",\n    \"typename\",\n    \"isunbounded\",\n    \"coverage_control\",\n    \"coverage_get\",\n    \"coverage_save\",\n    \"set_coverage_db_name\",\n    \"dimensions\",\n    \"right\",\n    \"high\",\n    \"size\",\n    \"random\",\n    \"dist_erlang\",\n    \"dist_normal\",\n    \"dist_t\",\n    \"asin\",\n    \"acos\",\n    \"atan\",\n    \"atan2\",\n    \"hypot\",\n    \"sinh\",\n    \"cosh\",\n    \"tanh\",\n    \"asinh\",\n    \"acosh\",\n    \"atanh\",\n    \"q_initialize\",\n    \"q_remove\",\n    \"q_exam\",\n    \"q_add\",\n    \"q_full\",\n    \"async$and$array\",\n    \"async$nand$array\",\n    \"async$or$array\",\n    \"async$nor$array\",\n    \"sync$and$array\",\n    \"sync$nand$array\",\n    \"sync$or$array\",\n    \"sync$nor$array\",\n    \"countones\",\n    \"onehot0\",\n    \"fatal\",\n    \"warning\",\n    \"dist_chi_square\",\n    \"dist_exponential\",\n    \"dist_poisson\",\n    \"dist_uniform\",\n    \"countbits\",\n    \"onehot\",\n    \"isunknown\",\n    \"coverage_get_max\",\n    \"coverage_merge\",\n    \"get_coverage\",\n    \"load_coverage_db\",\n    \"clog2\",\n    \"ln\",\n    \"log10\",\n    \"exp\",\n    \"sqrt\",\n    \"pow\",\n    \"floor\",\n    \"ceil\",\n    \"sin\",\n    \"cos\",\n    \"tan\",\n    \"rose\",\n    \"stable\",\n    \"past\",\n    \"rose_gclk\",\n    \"stable_gclk\",\n    \"future_gclk\",\n    \"falling_gclk\",\n    \"changing_gclk\",\n    \"unpacked_dimensions\",\n    \"left\",\n    \"low\",\n    \"increment\",\n    \"assertoff\",\n    \"assertcontrol\",\n    \"assertpassoff\",\n    \"assertfailoff\",\n    \"assertvacuousoff\",\n    \"error\",\n    \"info\",\n    \"async$and$plane\",\n    \"async$nand$plane\",\n    \"async$or$plane\",\n    \"async$nor$plane\",\n    \"sync$and$plane\",\n    \"sync$nand$plane\",\n    \"sync$or$plane\",\n    \"sync$nor$plane\",\n    \"system\",\n    \"countdrivers\",\n    \"getpattern\",\n    \"incsave\",\n    \"input\",\n    \"key\",\n    \"list\",\n    \"log\",\n    \"nokey\",\n    \"nolog\",\n    \"reset\",\n    \"reset_count\",\n    \"reset_value\",\n    \"restart\",\n    \"save\",\n    \"scale\",\n    \"scope\",\n    \"showscopes\",\n    \"showvars\",\n    \"sreadmemb\",\n    \"sreadmemh\",\n];\n\npub const DIRECTIVES: &[&str] = &[\n    \"__FILE__\",\n    \"__LINE__\",\n    \"begin_keywords\",\n    \"celldefine\",\n    \"default_nettype\",\n    \"define\",\n    \"else\",\n    \"elsif\",\n    \"end_keywords\",\n    \"endcelldefine\",\n    \"endif\",\n    \"ifdef\",\n    \"ifndef\",\n    \"include\",\n    \"line\",\n    \"nounconnected_drive\",\n    \"pragma\",\n    \"resetall\",\n    \"timescale\",\n    \"unconnected_drive\",\n    \"undef\",\n    \"undefineall\",\n    \"default_decay_time\",\n    \"default_trireg_strength\",\n    \"delay_mode_distributed\",\n    \"delay_mode_path\",\n    \"delay_mode_unit\",\n    \"delay_mode_zero\",\n];\n"
  },
  {
    "path": "src/completion.rs",
    "content": "use crate::server::LSPServer;\nuse crate::sources::LSPSupport;\nuse log::{debug, trace};\nuse ropey::{Rope, RopeSlice};\nuse std::time::Instant;\nuse tower_lsp::lsp_types::*;\n\npub mod keyword;\n\nimpl LSPServer {\n    pub fn completion(&self, params: CompletionParams) -> Option<CompletionResponse> {\n        debug!(\"completion requested\");\n        trace!(\"{:#?}\", &params);\n        let now = Instant::now();\n        let doc = params.text_document_position;\n        let file_id = self.srcs.get_id(&doc.text_document.uri).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        trace!(\"comp wait parse: {}\", now.elapsed().as_millis());\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n        trace!(\"comp read: {}\", now.elapsed().as_millis());\n        let token = get_completion_token(\n            &file.text,\n            file.text.line(doc.position.line as usize),\n            doc.position,\n        );\n        let response = match params.context {\n            Some(context) => match context.trigger_kind {\n                CompletionTriggerKind::TRIGGER_CHARACTER => {\n                    debug!(\n                        \"trigger char completion: {}\",\n                        context.trigger_character.clone()?.as_str()\n                    );\n                    match context.trigger_character?.as_str() {\n                        \".\" => Some(self.srcs.get_dot_completions(\n                            token.trim_end_matches('.'),\n                            file.text.pos_to_byte(&doc.position),\n                            &doc.text_document.uri,\n                        )?),\n                        \"$\" => Some(CompletionList {\n                            is_incomplete: false,\n                            items: self.sys_tasks.clone(),\n                        }),\n                        \"`\" => Some(CompletionList {\n                            is_incomplete: false,\n                            items: self.directives.clone(),\n                        }),\n                        _ => None,\n                    }\n                }\n                CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS => None,\n                CompletionTriggerKind::INVOKED => {\n                    debug!(\"Invoked Completion\");\n                    let mut comps = self.srcs.get_completions(\n                        &token,\n                        file.text.pos_to_byte(&doc.position),\n                        &doc.text_document.uri,\n                    )?;\n                    // complete keywords\n                    comps.items.extend::<Vec<CompletionItem>>(\n                        self.key_comps\n                            .iter()\n                            .filter(|x| x.label.starts_with(&token))\n                            .cloned()\n                            .collect(),\n                    );\n                    Some(comps)\n                }\n                _ => None,\n            },\n            None => {\n                let trigger = prev_char(&file.text, &doc.position);\n                match trigger {\n                    '.' => Some(self.srcs.get_dot_completions(\n                        token.trim_end_matches('.'),\n                        file.text.pos_to_byte(&doc.position),\n                        &doc.text_document.uri,\n                    )?),\n                    '$' => Some(CompletionList {\n                        is_incomplete: false,\n                        items: self.sys_tasks.clone(),\n                    }),\n                    '`' => Some(CompletionList {\n                        is_incomplete: false,\n                        items: self.directives.clone(),\n                    }),\n                    _ => {\n                        let mut comps = self.srcs.get_completions(\n                            &token,\n                            file.text.pos_to_byte(&doc.position),\n                            &doc.text_document.uri,\n                        )?;\n                        comps.items.extend::<Vec<CompletionItem>>(\n                            self.key_comps\n                                .iter()\n                                .filter(|x| x.label.starts_with(&token))\n                                .cloned()\n                                .collect(),\n                        );\n                        Some(comps)\n                    }\n                }\n            }\n        };\n        // eprintln!(\"comp response: {}\", now.elapsed().as_millis());\n        Some(CompletionResponse::List(response?))\n    }\n}\n\n/// get the previous non-whitespace character\nfn prev_char(text: &Rope, pos: &Position) -> char {\n    let char_idx = text.pos_to_char(pos);\n    if char_idx > 0 {\n        for i in (0..char_idx).rev() {\n            let res = text.char(i);\n            if !res.is_whitespace() {\n                return res;\n            }\n        }\n        ' '\n    } else {\n        ' '\n    }\n}\n\n/// attempt to get the token the user was trying to complete, by\n/// filtering out characters unneeded for name resolution\nfn get_completion_token(text: &Rope, line: RopeSlice, pos: Position) -> String {\n    let mut token = String::new();\n    let mut line_iter = line.chars();\n    for _ in 0..(line.utf16_cu_to_char(pos.character as usize)) {\n        line_iter.next();\n    }\n    let mut c = line_iter.prev();\n    //TODO: make this a regex\n    while c.is_some()\n        && (c.unwrap().is_alphanumeric()\n            || c.unwrap() == '_'\n            || c.unwrap() == '.'\n            || c.unwrap() == '['\n            || c.unwrap() == ']')\n    {\n        token.push(c.unwrap());\n        c = line_iter.prev();\n    }\n    let mut result: String = token.chars().rev().collect();\n    if result.contains('[') {\n        let l_bracket_offset = result.find('[').unwrap_or(result.len());\n        result.replace_range(l_bracket_offset.., \"\");\n    }\n    if &result == \".\" {\n        // probably a instantiation, the token should be what we're instatiating\n        let mut char_iter = text.chars();\n        let mut token = String::new();\n        for _ in 0..text.pos_to_char(&pos) {\n            char_iter.next();\n        }\n        let mut c = char_iter.prev();\n\n        // go to the last semicolon\n        while c.is_some() && (c.unwrap() != ';') {\n            c = char_iter.prev();\n        }\n        // go the the start of the next symbol\n        while c.is_some() && !(c.unwrap().is_alphanumeric() || c.unwrap() == '_') {\n            c = char_iter.next();\n        }\n        // then extract the next symbol\n        while c.is_some() && (c.unwrap().is_alphanumeric() || c.unwrap() == '_') {\n            token.push(c.unwrap());\n            c = char_iter.next();\n        }\n        token\n    } else {\n        result\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::definition::def_types::Scope;\n    use crate::definition::get_scopes;\n    use crate::sources::{parse, LSPSupport};\n    use crate::support::test_init;\n    use ropey::Rope;\n\n    #[test]\n    fn test_get_completion_token() {\n        test_init();\n        let text = Rope::from_str(\"abc abc.cba de_fg cde[4]\");\n        let mut result = get_completion_token(\n            &text,\n            text.line(0),\n            Position {\n                line: 0,\n                character: 3,\n            },\n        );\n        assert_eq!(&result, \"abc\");\n        result = get_completion_token(\n            &text,\n            text.line(0),\n            Position {\n                line: 0,\n                character: 11,\n            },\n        );\n        assert_eq!(&result, \"abc.cba\");\n        result = get_completion_token(\n            &text,\n            text.line(0),\n            Position {\n                line: 0,\n                character: 16,\n            },\n        );\n        assert_eq!(&result, \"de_f\");\n        result = get_completion_token(\n            &text,\n            text.line(0),\n            Position {\n                line: 0,\n                character: 23,\n            },\n        );\n        assert_eq!(&result, \"cde\");\n    }\n\n    #[test]\n    fn test_completion() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"module test;\n    logic abc;\n    logic abcd;\n\nendmodule\n\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n        server.srcs.wait_parse_ready(fid, true);\n\n        let change_params = DidChangeTextDocumentParams {\n            text_document: VersionedTextDocumentIdentifier {\n                uri: uri.clone(),\n                version: 3,\n            },\n            content_changes: vec![\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 3,\n                            character: 0,\n                        },\n                        end: Position {\n                            line: 3,\n                            character: 0,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"\\n\".to_owned(),\n                },\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                        end: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"  \".to_owned(),\n                },\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 4,\n                            character: 2,\n                        },\n                        end: Position {\n                            line: 4,\n                            character: 2,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"a\".to_owned(),\n                },\n            ],\n        };\n        server.did_change(change_params);\n        server.srcs.wait_parse_ready(fid, true);\n\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri },\n                position: Position {\n                    line: 4,\n                    character: 3,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::INVOKED,\n                trigger_character: None,\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        let item1 = CompletionItem {\n            label: \"abc\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"logic\".to_string()),\n            ..CompletionItem::default()\n        };\n        let item2 = CompletionItem {\n            label: \"abcd\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"logic\".to_string()),\n            ..CompletionItem::default()\n        };\n        if let CompletionResponse::List(item) = response {\n            assert!(item.items.contains(&item1));\n            assert!(item.items.contains(&item2));\n        } else {\n            panic!();\n        }\n    }\n\n    #[test]\n    fn test_nested_completion() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"module test;\n    logic aouter;\n    function func1();\n        logic abc;\n        func1 = abc;\n    endfunction\n    function func2();\n        logic abcd;\n        func2 = abcd;\n    endfunction\nendmodule\n\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n        server.srcs.wait_parse_ready(fid, true);\n\n        let change_params = DidChangeTextDocumentParams {\n            text_document: VersionedTextDocumentIdentifier {\n                uri: uri.clone(),\n                version: 3,\n            },\n            content_changes: vec![\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                        end: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"\\n\".to_owned(),\n                },\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                        end: Position {\n                            line: 4,\n                            character: 0,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"  \".to_owned(),\n                },\n                TextDocumentContentChangeEvent {\n                    range: Some(Range {\n                        start: Position {\n                            line: 4,\n                            character: 2,\n                        },\n                        end: Position {\n                            line: 4,\n                            character: 2,\n                        },\n                    }),\n                    range_length: None,\n                    text: \"a\".to_owned(),\n                },\n            ],\n        };\n        server.did_change(change_params);\n        server.srcs.wait_parse_ready(fid, true);\n\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri },\n                position: Position {\n                    line: 4,\n                    character: 3,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::INVOKED,\n                trigger_character: None,\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        let item1 = CompletionItem {\n            label: \"abc\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"logic\".to_string()),\n            ..CompletionItem::default()\n        };\n        let item3 = CompletionItem {\n            label: \"aouter\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"logic\".to_string()),\n            ..CompletionItem::default()\n        };\n        if let CompletionResponse::List(item) = response {\n            eprintln!(\"{:#?}\", item);\n            assert!(item.items.contains(&item1));\n            for comp in &item.items {\n                assert!(comp.label != \"abcd\");\n            }\n            assert!(item.items.contains(&item3));\n        } else {\n            panic!();\n        }\n    }\n\n    #[test]\n    fn test_dot_completion() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"interface test_inter;\n    wire abcd;\nendinterface\nmodule test(\n    test_inter abc\n);\n    abc.\n    test_inter.\nendmodule\n\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n        server.srcs.wait_parse_ready(fid, true);\n        let file = server.srcs.get_file(fid).unwrap();\n        let file = file.read().unwrap();\n        eprintln!(\"{}\", file.syntax_tree.as_ref().unwrap());\n        eprintln!(\n            \"{:#?}\",\n            server.srcs.scope_tree.read().unwrap().as_ref().unwrap()\n        );\n\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri: uri.clone() },\n                position: Position {\n                    line: 6,\n                    character: 8,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER,\n                trigger_character: Some(\".\".to_string()),\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        dbg!(&response);\n        let item1 = CompletionItem {\n            label: \"abcd\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"wire\".to_string()),\n            ..CompletionItem::default()\n        };\n        if let CompletionResponse::List(item) = response {\n            eprintln!(\"{:#?}\", item);\n            assert!(item.items.contains(&item1));\n            assert!(item.items.len() == 1);\n        } else {\n            panic!();\n        }\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri },\n                position: Position {\n                    line: 7,\n                    character: 14,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER,\n                trigger_character: Some(\".\".to_string()),\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        if let CompletionResponse::List(item) = response {\n            eprintln!(\"{:#?}\", item);\n            assert!(item.items.contains(&item1));\n            assert!(item.items.len() == 1);\n        } else {\n            panic!();\n        }\n    }\n\n    #[test]\n    fn test_trigger_dot_nocontext() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"interface test_inter;\n    wire abcd;\nendinterface\nmodule test(\n    test_inter abc\n);\n    abc.\n    test_inter.\nendmodule\n\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n        server.srcs.wait_parse_ready(fid, true);\n        let file = server.srcs.get_file(fid).unwrap();\n        let file = file.read().unwrap();\n        eprintln!(\"{}\", file.syntax_tree.as_ref().unwrap());\n        eprintln!(\n            \"{:#?}\",\n            server.srcs.scope_tree.read().unwrap().as_ref().unwrap()\n        );\n\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri: uri.clone() },\n                position: Position {\n                    line: 6,\n                    character: 8,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: None,\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        dbg!(&response);\n        let item1 = CompletionItem {\n            label: \"abcd\".to_owned(),\n            kind: Some(CompletionItemKind::VARIABLE),\n            detail: Some(\"wire\".to_string()),\n            ..CompletionItem::default()\n        };\n        if let CompletionResponse::List(item) = response {\n            eprintln!(\"{:#?}\", item);\n            assert!(item.items.contains(&item1));\n            assert!(item.items.len() == 1);\n        } else {\n            panic!();\n        }\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri },\n                position: Position {\n                    line: 7,\n                    character: 14,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER,\n                trigger_character: Some(\".\".to_string()),\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        if let CompletionResponse::List(item) = response {\n            eprintln!(\"{:#?}\", item);\n            assert!(item.items.contains(&item1));\n            assert!(item.items.len() == 1);\n        } else {\n            panic!();\n        }\n    }\n\n    #[test]\n    fn test_dot_completion_instantiation() {\n        test_init();\n        let text = r#\"interface test_inter;\n    wire wrong;\n    logic clk;\nendinterface\nmodule test;\n    logic clk;\n    test_inter2 t (\n        .clk(clk),\n        .\n    )\nendmodule\ninterface test_inter2;\n    wire abcd;\n    logic clk;\nendinterface\n\"#;\n\n        let doc = Rope::from_str(text);\n        let url = Url::parse(\"file:///test.sv\").unwrap();\n        let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();\n        let scope_tree = get_scopes(&syntax_tree, &url).unwrap();\n        let pos = Position::new(8, 9);\n        let token = get_completion_token(&doc, doc.line(pos.line as usize), pos);\n        let completions = scope_tree.get_dot_completion(\n            token.trim_end_matches('.'),\n            doc.pos_to_byte(&pos),\n            &url,\n            &scope_tree,\n        );\n        let labels: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();\n        assert_eq!(labels, vec![\"abcd\", \"clk\"]);\n    }\n\n    /*\n        #[test]\n        fn test_package_completion() {\n            test_init();\n            let text = r#\"package p;\n      struct {int x;} s1;\n      struct {int x;} s2;\n      function void f();\n        int x;\n      endfunction\n    endpackage\n    module m;\n      import p::*;\n      if (1) begin : s1\n        initial begin\n          s1.x = 1;\n          f.x  = 1;\n        end\n        int x;\n      end\n    endmodule\n    \"#;\n\n            let doc = Rope::from_str(&text);\n            let url = Url::parse(\"file:///test.sv\").unwrap();\n            let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();\n            let scope_tree = get_scopes(&syntax_tree, &url).unwrap();\n            dbg!(&scope_tree);\n            /*\n            let pos = Position::new(8, 9);\n            let token = get_completion_token(&doc, doc.line(pos.line as usize), pos);\n            let completions = scope_tree.get_dot_completion(\n                token.trim_end_matches('.'),\n                doc.pos_to_byte(&pos),\n                &url,\n                &scope_tree,\n            );\n            let labels: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();\n            assert_eq!(labels, vec![\"abcd\", \"clk\"]);\n            */\n            panic!();\n        }\n        */\n\n    #[test]\n    fn test_inter_file_completion() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let uri2 = Url::parse(\"file:///test2.sv\").unwrap();\n        let text = r#\"module test;\n    s\nendmodule\n\"#;\n        let text2 = r#\"interface simple_bus;\n    logic clk;\nendinterface\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        let open_params2 = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri2.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text2.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        server.did_open(open_params2);\n        let fid = server.srcs.get_id(&uri);\n        let fid2 = server.srcs.get_id(&uri2);\n        server.srcs.wait_parse_ready(fid, true);\n        server.srcs.wait_parse_ready(fid2, true);\n\n        let completion_params = CompletionParams {\n            text_document_position: TextDocumentPositionParams {\n                text_document: TextDocumentIdentifier { uri },\n                position: Position {\n                    line: 1,\n                    character: 5,\n                },\n            },\n            work_done_progress_params: WorkDoneProgressParams::default(),\n            partial_result_params: PartialResultParams::default(),\n            context: Some(CompletionContext {\n                trigger_kind: CompletionTriggerKind::INVOKED,\n                trigger_character: None,\n            }),\n        };\n        let response: CompletionResponse = server.completion(completion_params).unwrap();\n        let scope_tree = server.srcs.scope_tree.read().unwrap();\n        dbg!(scope_tree.as_ref().unwrap());\n        if let CompletionResponse::List(item) = response {\n            // eprintln!(\"{:#?}\", item);\n            let names: Vec<&String> = item.items.iter().map(|x| &x.label).collect();\n            assert!(names.contains(&&\"simple_bus\".to_string()));\n        } else {\n            panic!();\n        }\n    }\n}\n"
  },
  {
    "path": "src/definition/def_types.rs",
    "content": "use crate::sources::LSPSupport;\nuse log::trace;\nuse ropey::Rope;\nuse tower_lsp::lsp_types::*;\n\n/// cleanup the text of a definition so it can be included in completions\npub fn clean_type_str(type_str: &str, ident: &str) -> String {\n    let endings: &[_] = &[';', ','];\n    // remove anything after an equals sign\n    let eq_offset = type_str.find('=').unwrap_or(type_str.len());\n    let mut result = type_str.to_string();\n    result.replace_range(eq_offset.., \"\");\n    result\n        .trim_start()\n        .trim_end()\n        .trim_end_matches(endings)\n        .trim_end_matches(ident)\n        .split_whitespace()\n        .collect::<Vec<&str>>()\n        .join(\" \")\n        .replace(\"[ \", \"[\")\n        .replace(\" ]\", \"]\")\n        .replace(\" : \", \":\")\n}\n\npub fn copy_defs(defs: &[Box<dyn Definition>]) -> Vec<Box<dyn Definition>> {\n    let mut decs: Vec<Box<dyn Definition>> = Vec::new();\n    for def in defs {\n        decs.push(Box::new(GenericDec {\n            ident: def.ident(),\n            byte_idx: def.byte_idx(),\n            url: def.url(),\n            type_str: def.type_str(),\n            completion_kind: def.completion_kind(),\n            symbol_kind: def.symbol_kind(),\n            def_type: def.def_type(),\n        }))\n    }\n    decs\n}\n\npub fn copy_scopes(scopes: &[Box<dyn Scope>]) -> Vec<Box<dyn Scope>> {\n    let mut scope_decs: Vec<Box<dyn Scope>> = Vec::new();\n    for scope in scopes {\n        let mut scope_copy = GenericScope {\n            ident: scope.ident(),\n            byte_idx: scope.byte_idx(),\n            start: scope.start(),\n            end: scope.end(),\n            url: scope.url(),\n            type_str: scope.type_str(),\n            completion_kind: scope.completion_kind(),\n            symbol_kind: scope.symbol_kind(),\n            def_type: scope.def_type(),\n            defs: Vec::new(),\n            scopes: Vec::new(),\n        };\n        scope_copy.defs.extend(copy_defs(scope.defs()));\n        scope_copy.scopes.extend(copy_scopes(scope.scopes()));\n        scope_decs.push(Box::new(scope_copy))\n    }\n    scope_decs\n}\n\n/// A definition of any SystemVerilog variable or construct\npub trait Definition: std::fmt::Debug + Sync + Send {\n    // identifier\n    fn ident(&self) -> String;\n    // byte index in file of definition\n    fn byte_idx(&self) -> usize;\n    // url pointing to the file the definition is in\n    fn url(&self) -> Url;\n    // cleaned up text of the definition\n    fn type_str(&self) -> String;\n    // the kind of this definition, for use in completions\n    fn completion_kind(&self) -> CompletionItemKind;\n    // the kind of this definition, for use in showing document symbols\n    // for some reason this kind is different than CompletionItemKind\n    fn symbol_kind(&self) -> SymbolKind;\n    // the kind of this definition, simplified for internal use\n    fn def_type(&self) -> DefinitionType;\n    // whether the definition identifier starts with the given token\n    fn starts_with(&self, token: &str) -> bool;\n    // constructs the completion for this definition\n    fn completion(&self) -> CompletionItem;\n    fn dot_completion(&self, scope_tree: &GenericScope) -> Vec<CompletionItem>;\n}\n\npub trait Scope: std::fmt::Debug + Definition + Sync + Send {\n    // the start byte of this scope\n    fn start(&self) -> usize;\n    // the end byte of this scope\n    fn end(&self) -> usize;\n    // all the within this scope\n    fn defs(&self) -> &Vec<Box<dyn Definition>>;\n    // all the scopes within this scope, ex. task inside a module\n    fn scopes(&self) -> &Vec<Box<dyn Scope>>;\n    // the definition of this scope\n    fn definition(&self) -> GenericDec {\n        GenericDec {\n            ident: self.ident(),\n            byte_idx: self.byte_idx(),\n            url: self.url(),\n            type_str: self.type_str(),\n            completion_kind: self.completion_kind(),\n            symbol_kind: self.symbol_kind(),\n            def_type: DefinitionType::GenericScope,\n        }\n    }\n    /// return a completion from the scope tree, this function should be called on the global scope\n    fn get_completion(&self, token: &str, byte_idx: usize, url: &Url) -> Vec<CompletionItem> {\n        let mut completions: Vec<CompletionItem> = Vec::new();\n        // first we need to go down the scope tree, to the scope the user is invoking a completion\n        // in\n        for scope in self.scopes() {\n            if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {\n                completions = scope.get_completion(token, byte_idx, url);\n                break;\n            }\n        }\n        // now that we are in the users scope, we can attempt to find a relevant completion\n        // we proceed back upwards through the scope tree, adding any definitions that match\n        // the users token\n        let completion_idents: Vec<String> = completions.iter().map(|x| x.label.clone()).collect();\n        for def in self.defs() {\n            if !completion_idents.contains(&def.ident()) && def.starts_with(token) {\n                completions.push(def.completion());\n            }\n        }\n        for scope in self.scopes() {\n            if scope.starts_with(token) {\n                completions.push(scope.completion());\n            }\n        }\n        completions\n    }\n\n    /// return a dot completion from the scope tree, this function should be called on the global\n    /// scope\n    fn get_dot_completion(\n        &self,\n        token: &str,\n        byte_idx: usize,\n        url: &Url,\n        scope_tree: &GenericScope,\n    ) -> Vec<CompletionItem> {\n        trace!(\"dot entering: {}, token: {}\", self.ident(), token);\n        trace!(\"{:?}\", self.scopes());\n        // first we need to go down the scope tree, to the scope the user is invoking a completion\n        // in\n        for scope in self.scopes() {\n            trace!(\n                \"{}, {}, {}, {}\",\n                scope.ident(),\n                byte_idx,\n                scope.start(),\n                scope.end()\n            );\n            if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {\n                eprintln!(\"checking dot completion: {}\", scope.ident());\n                let result = scope.get_dot_completion(token, byte_idx, url, scope_tree);\n                if !result.is_empty() {\n                    return result;\n                }\n            }\n        }\n        // now that we are in the users scope, we can attempt to find the relevant definition\n        // we proceed back upwards through the scope tree, and if a definition matches our token,\n        // we invoke dot completion on that definition and pass it the syntax tree\n        for def in self.defs() {\n            trace!(\"def: {:?}\", def);\n            if def.starts_with(token) {\n                trace!(\"complete def: {:?}\", def);\n                return def.dot_completion(scope_tree);\n            }\n        }\n        for scope in self.scopes() {\n            if scope.starts_with(token) {\n                trace!(\"found dot-completion scope: {}\", scope.ident());\n                return scope.dot_completion(scope_tree);\n            }\n        }\n        Vec::new()\n    }\n\n    /// return a definition from the scope tree, this function should be called on the global\n    /// scope\n    fn get_definition(&self, token: &str, byte_idx: usize, url: &Url) -> Option<GenericDec> {\n        let mut definition: Option<GenericDec> = None;\n        for scope in self.scopes() {\n            if &scope.url() == url && scope.start() <= byte_idx && byte_idx <= scope.end() {\n                definition = scope.get_definition(token, byte_idx, url);\n                break;\n            }\n        }\n        if definition.is_none() {\n            for def in self.defs() {\n                if def.ident() == token {\n                    return Some(GenericDec {\n                        ident: def.ident(),\n                        byte_idx: def.byte_idx(),\n                        url: def.url(),\n                        type_str: def.type_str(),\n                        completion_kind: def.completion_kind(),\n                        symbol_kind: def.symbol_kind(),\n                        def_type: DefinitionType::Net,\n                    });\n                }\n            }\n            for scope in self.scopes() {\n                if scope.ident() == token {\n                    return Some(scope.definition());\n                }\n            }\n        }\n        definition\n    }\n    /// returns all symbols in a document\n    fn document_symbols(&self, uri: &Url, doc: &Rope) -> Vec<DocumentSymbol> {\n        let mut symbols: Vec<DocumentSymbol> = Vec::new();\n        for scope in self.scopes() {\n            if &scope.url() == uri {\n                #[allow(deprecated)]\n                symbols.push(DocumentSymbol {\n                    name: scope.ident(),\n                    detail: Some(scope.type_str()),\n                    kind: scope.symbol_kind(),\n                    deprecated: None,\n                    range: Range::new(doc.byte_to_pos(scope.start()), doc.byte_to_pos(scope.end())),\n                    selection_range: Range::new(\n                        doc.byte_to_pos(scope.byte_idx()),\n                        doc.byte_to_pos(scope.byte_idx() + scope.ident().len()),\n                    ),\n                    children: Some(scope.document_symbols(uri, doc)),\n                    tags: None,\n                })\n            }\n        }\n        for def in self.defs() {\n            #[allow(deprecated)]\n            symbols.push(DocumentSymbol {\n                name: def.ident(),\n                detail: Some(def.type_str()),\n                kind: def.symbol_kind(),\n                deprecated: None,\n                range: Range::new(\n                    doc.byte_to_pos(def.byte_idx()),\n                    doc.byte_to_pos(def.byte_idx() + def.ident().len()),\n                ),\n                selection_range: Range::new(\n                    doc.byte_to_pos(def.byte_idx()),\n                    doc.byte_to_pos(def.byte_idx() + def.ident().len()),\n                ),\n                children: None,\n                tags: None,\n            })\n        }\n        symbols\n    }\n\n    /// highlight all references of a symbol\n    fn document_highlights(\n        &self,\n        uri: &Url,\n        doc: &Rope,\n        // all references in the doc's syntax tree\n        references: Vec<(String, usize)>,\n        // byte_idx of symbol definition\n        byte_idx: usize,\n    ) -> Vec<DocumentHighlight> {\n        // to find references we need to grab references from locations downward from the\n        // definition\n        for scope in self.scopes() {\n            if &scope.url() == uri && scope.start() <= byte_idx && byte_idx <= scope.end() {\n                return scope.document_highlights(uri, doc, references, byte_idx);\n            }\n        }\n        // we should now be in the scope of the definition, so we can grab all references\n        // in this scope. This also grabs references below this scope.\n        references\n            .iter()\n            .filter(|x| self.start() <= x.1 && x.1 <= self.end())\n            .map(|x| DocumentHighlight {\n                range: Range::new(doc.byte_to_pos(x.1), doc.byte_to_pos(x.1 + x.0.len())),\n                kind: None,\n            })\n            .collect()\n    }\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum DefinitionType {\n    Port,\n    Net,\n    Data,\n    Modport,\n    Subroutine,\n    ModuleInstantiation,\n    GenericScope,\n    Class,\n}\n\n#[derive(Debug)]\npub struct PortDec {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub interface: Option<String>,\n    pub modport: Option<String>,\n}\n\nimpl PortDec {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::PROPERTY,\n            symbol_kind: SymbolKind::PROPERTY,\n            def_type: DefinitionType::Port,\n            interface: None,\n            modport: None,\n            url: url.clone(),\n        }\n    }\n}\n\nimpl Definition for PortDec {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, scope_tree: &GenericScope) -> Vec<CompletionItem> {\n        for scope in &scope_tree.scopes {\n            if let Some(interface) = &self.interface {\n                if &scope.ident() == interface {\n                    return match &self.modport {\n                        Some(modport) => {\n                            for def in scope.defs() {\n                                if def.starts_with(modport) {\n                                    return def.dot_completion(scope_tree);\n                                }\n                            }\n                            Vec::new()\n                        }\n                        None => scope\n                            .defs()\n                            .iter()\n                            .filter(|x| !x.starts_with(&scope.ident()))\n                            .map(|x| x.completion())\n                            .collect(),\n                    };\n                }\n            }\n        }\n        Vec::new()\n    }\n}\n\n#[derive(Debug)]\npub struct GenericDec {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n}\n\nimpl GenericDec {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::VARIABLE,\n            // FIXME: check if this replacement is correct\n            symbol_kind: SymbolKind::NULL,\n            def_type: DefinitionType::Net,\n        }\n    }\n}\n\nimpl Definition for GenericDec {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, _: &GenericScope) -> Vec<CompletionItem> {\n        Vec::new()\n    }\n}\n\n#[derive(Debug)]\npub struct PackageImport {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub asterisk: bool,\n    pub import_ident: Option<String>,\n}\n\nimpl PackageImport {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::TEXT,\n            symbol_kind: SymbolKind::NAMESPACE,\n            def_type: DefinitionType::Data,\n            asterisk: false,\n            import_ident: None,\n        }\n    }\n}\n\nimpl Definition for PackageImport {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident.clone())),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, _: &GenericScope) -> Vec<CompletionItem> {\n        Vec::new()\n    }\n}\n\n#[derive(Debug)]\npub struct SubDec {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub start: usize,\n    pub end: usize,\n    pub defs: Vec<Box<dyn Definition>>,\n    pub scopes: Vec<Box<dyn Scope>>,\n}\n\nimpl SubDec {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::FUNCTION,\n            symbol_kind: SymbolKind::FUNCTION,\n            def_type: DefinitionType::Subroutine,\n            start: 0,\n            end: 0,\n            defs: Vec::new(),\n            scopes: Vec::new(),\n        }\n    }\n}\n\nimpl Definition for SubDec {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, _: &GenericScope) -> Vec<CompletionItem> {\n        Vec::new()\n    }\n}\n\nimpl Scope for SubDec {\n    fn start(&self) -> usize {\n        self.start\n    }\n\n    fn end(&self) -> usize {\n        self.end\n    }\n    fn defs(&self) -> &Vec<Box<dyn Definition>> {\n        &self.defs\n    }\n\n    fn scopes(&self) -> &Vec<Box<dyn Scope>> {\n        &self.scopes\n    }\n}\n\n#[derive(Debug)]\npub struct ModportDec {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub ports: Vec<Box<dyn Definition>>,\n}\n\nimpl ModportDec {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::INTERFACE,\n            symbol_kind: SymbolKind::INTERFACE,\n            def_type: DefinitionType::Modport,\n            ports: Vec::new(),\n        }\n    }\n}\n\nimpl Definition for ModportDec {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, _: &GenericScope) -> Vec<CompletionItem> {\n        self.ports.iter().map(|x| x.completion()).collect()\n    }\n}\n\n#[derive(Debug)]\npub struct ModInst {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub mod_ident: String,\n}\n\nimpl ModInst {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::MODULE,\n            symbol_kind: SymbolKind::MODULE,\n            def_type: DefinitionType::ModuleInstantiation,\n            mod_ident: String::new(),\n        }\n    }\n}\n\nimpl Definition for ModInst {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, scope_tree: &GenericScope) -> Vec<CompletionItem> {\n        for scope in &scope_tree.scopes {\n            if scope.ident() == self.mod_ident {\n                return scope\n                    .defs()\n                    .iter()\n                    .filter(|x| !x.starts_with(&scope.ident()))\n                    .map(|x| x.completion())\n                    .collect();\n            }\n        }\n        Vec::new()\n    }\n}\n\n#[derive(Debug)]\npub struct GenericScope {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub start: usize,\n    pub end: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub defs: Vec<Box<dyn Definition>>,\n    pub scopes: Vec<Box<dyn Scope>>,\n}\n\nimpl GenericScope {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            start: 0,\n            end: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::MODULE,\n            symbol_kind: SymbolKind::MODULE,\n            def_type: DefinitionType::GenericScope,\n            defs: Vec::new(),\n            scopes: Vec::new(),\n        }\n    }\n\n    #[cfg(test)]\n    pub fn contains_scope(&self, scope_ident: &str) -> bool {\n        for scope in &self.scopes {\n            if scope.starts_with(scope_ident) {\n                return true;\n            }\n        }\n        false\n    }\n}\n\nimpl Definition for GenericScope {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, scope_tree: &GenericScope) -> Vec<CompletionItem> {\n        for scope in scope_tree.scopes() {\n            if scope.ident() == self.ident {\n                return scope\n                    .defs()\n                    .iter()\n                    .filter(|x| !x.starts_with(&scope.ident()))\n                    .map(|x| x.completion())\n                    .collect();\n            }\n        }\n        Vec::new()\n    }\n}\n\nimpl Scope for GenericScope {\n    fn start(&self) -> usize {\n        self.start\n    }\n\n    fn end(&self) -> usize {\n        self.end\n    }\n\n    fn defs(&self) -> &Vec<Box<dyn Definition>> {\n        &self.defs\n    }\n\n    fn scopes(&self) -> &Vec<Box<dyn Scope>> {\n        &self.scopes\n    }\n}\n\n#[derive(Debug)]\npub struct ClassDec {\n    pub ident: String,\n    pub byte_idx: usize,\n    pub start: usize,\n    pub end: usize,\n    pub url: Url,\n    pub type_str: String,\n    pub completion_kind: CompletionItemKind,\n    pub symbol_kind: SymbolKind,\n    pub def_type: DefinitionType,\n    pub defs: Vec<Box<dyn Definition>>,\n    pub scopes: Vec<Box<dyn Scope>>,\n    // class, package\n    pub extends: (Vec<String>, Option<String>),\n    // class, package\n    pub implements: Vec<(String, Option<String>)>,\n}\n\nimpl ClassDec {\n    pub fn new(url: &Url) -> Self {\n        Self {\n            ident: String::new(),\n            byte_idx: 0,\n            start: 0,\n            end: 0,\n            url: url.clone(),\n            type_str: String::new(),\n            completion_kind: CompletionItemKind::CLASS,\n            symbol_kind: SymbolKind::CLASS,\n            def_type: DefinitionType::Class,\n            defs: Vec::new(),\n            scopes: Vec::new(),\n            extends: (Vec::new(), None),\n            implements: Vec::new(),\n        }\n    }\n}\n\nimpl Definition for ClassDec {\n    fn ident(&self) -> String {\n        self.ident.clone()\n    }\n    fn byte_idx(&self) -> usize {\n        self.byte_idx\n    }\n    fn url(&self) -> Url {\n        self.url.clone()\n    }\n    fn type_str(&self) -> String {\n        self.type_str.clone()\n    }\n    fn completion_kind(&self) -> CompletionItemKind {\n        self.completion_kind\n    }\n    fn symbol_kind(&self) -> SymbolKind {\n        self.symbol_kind\n    }\n    fn def_type(&self) -> DefinitionType {\n        self.def_type\n    }\n    fn starts_with(&self, token: &str) -> bool {\n        self.ident.starts_with(token)\n    }\n    fn completion(&self) -> CompletionItem {\n        CompletionItem {\n            label: self.ident.clone(),\n            detail: Some(clean_type_str(&self.type_str, &self.ident)),\n            kind: Some(self.completion_kind),\n            ..CompletionItem::default()\n        }\n    }\n    fn dot_completion(&self, scope_tree: &GenericScope) -> Vec<CompletionItem> {\n        for scope in scope_tree.scopes() {\n            if scope.ident() == self.ident {\n                return scope\n                    .defs()\n                    .iter()\n                    .filter(|x| !x.starts_with(&scope.ident()))\n                    .map(|x| x.completion())\n                    .collect();\n            }\n        }\n        Vec::new()\n    }\n}\n\nimpl Scope for ClassDec {\n    fn start(&self) -> usize {\n        self.start\n    }\n\n    fn end(&self) -> usize {\n        self.end\n    }\n\n    fn defs(&self) -> &Vec<Box<dyn Definition>> {\n        &self.defs\n    }\n\n    fn scopes(&self) -> &Vec<Box<dyn Scope>> {\n        &self.scopes\n    }\n}\n"
  },
  {
    "path": "src/definition/extract_defs.rs",
    "content": "use crate::definition::def_types::*;\nuse crate::definition::match_definitions;\nuse sv_parser::*;\nuse tower_lsp::lsp_types::*;\n\npub fn get_ident(tree: &SyntaxTree, node: RefNode) -> (String, usize) {\n    let loc = unwrap_locate!(node).unwrap();\n    let ident_str = tree.get_str(loc).unwrap().to_string();\n    let byte_idx = tree.get_origin(loc).unwrap().1;\n    (ident_str, byte_idx)\n}\n\nfn get_loc(tree: &SyntaxTree, node: RefNode) -> usize {\n    let loc = unwrap_locate!(node).unwrap();\n    tree.get_origin(loc).unwrap().1\n}\n\nmacro_rules! advance_until_leave {\n    ($tokens:ident, $tree:ident, $event_iter:ident, $node:path) => {{\n        let mut result: Option<RefNode> = None;\n        while let Some(event) = $event_iter.next() {\n            match event {\n                NodeEvent::Leave(x) => match x {\n                    $node(node) => {\n                        result = Some($node(node));\n                        break;\n                    }\n                    RefNode::Locate(node) => {\n                        $tokens.push(' ');\n                        $tokens.push_str($tree.get_str(node)?);\n                    }\n                    _ => (),\n                },\n                NodeEvent::Enter(_) => (),\n            }\n        }\n        result\n    }};\n}\n\nmacro_rules! advance_until_enter {\n    ($tokens:ident, $tree:ident, $event_iter:ident, $node:path, $type:ty) => {{\n        let mut result: Option<$type> = None;\n        while let Some(event) = $event_iter.next() {\n            match event {\n                NodeEvent::Enter(x) => match x {\n                    $node(node) => {\n                        result = Some(node);\n                        break;\n                    }\n                    RefNode::Locate(node) => {\n                        $tokens.push(' ');\n                        $tokens.push_str($tree.get_str(node)?);\n                    }\n                    _ => (),\n                },\n                NodeEvent::Leave(_) => (),\n            }\n        }\n        result\n    }};\n}\n\nmacro_rules! skip_until_enter {\n    ($tree:ident, $event_iter:ident, $node:path, $type:ty) => {{\n        let mut result: Option<$type> = None;\n        while let Some(event) = $event_iter.next() {\n            match event {\n                NodeEvent::Enter(x) => match x {\n                    $node(node) => {\n                        result = Some(node);\n                        break;\n                    }\n                    _ => (),\n                },\n                NodeEvent::Leave(_) => (),\n            }\n        }\n        result\n    }};\n}\n\nmacro_rules! skip_until_leave {\n    ($tree:ident, $event_iter:ident, $node:path) => {\n        while let Some(event) = $event_iter.next() {\n            match event {\n                NodeEvent::Enter(_) => (),\n                NodeEvent::Leave(x) => match x {\n                    $node(_) => {\n                        break;\n                    }\n                    _ => (),\n                },\n            }\n        }\n    };\n}\n\nmacro_rules! match_until_leave {\n    ($tree:ident, $event_iter:ident, $url:ident, $node:path) => {{\n        let mut scopes: Vec<Box<dyn Scope>> = Vec::new();\n        let mut definitions: Vec<Box<dyn Definition>> = Vec::new();\n        let mut global_scope: GenericScope = GenericScope::new($url);\n        global_scope.ident = \"global\".to_string();\n        while let Some(event) = $event_iter.next() {\n            match event {\n                NodeEvent::Enter(node) => {\n                    let mut result = match_definitions($tree, $event_iter, node, $url)?;\n                    definitions.append(&mut result.1);\n                    scopes.append(&mut result.0);\n                }\n                NodeEvent::Leave(node) => match node {\n                    $node(_) => {\n                        break;\n                    }\n                    _ => {}\n                },\n            }\n        }\n        Some((scopes, definitions))\n    }};\n}\n\npub fn port_dec_ansi(\n    tree: &SyntaxTree,\n    node: &AnsiPortDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<PortDec> {\n    let mut port = PortDec::new(url);\n    let mut tokens = String::new();\n    match node {\n        AnsiPortDeclaration::Net(x) => {\n            let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.1));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n            if let Some(NetPortHeaderOrInterfacePortHeader::InterfacePortHeader(z)) = &x.nodes.0 {\n                match &**z {\n                    InterfacePortHeader::Identifier(node) => {\n                        port.interface =\n                            Some(get_ident(tree, RefNode::InterfaceIdentifier(&node.nodes.0)).0);\n                        if let Some((_, mod_ident)) = &node.nodes.1 {\n                            port.modport =\n                                Some(get_ident(tree, RefNode::ModportIdentifier(mod_ident)).0);\n                        }\n                    }\n                    InterfacePortHeader::Interface(node) => {\n                        port.interface = Some(\"interface\".to_string());\n                        if let Some((_, mod_ident)) = &node.nodes.1 {\n                            port.modport =\n                                Some(get_ident(tree, RefNode::ModportIdentifier(mod_ident)).0);\n                        }\n                    }\n                }\n            }\n        }\n        AnsiPortDeclaration::Variable(x) => {\n            let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.1));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n        }\n        AnsiPortDeclaration::Paren(x) => {\n            let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.2));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n        }\n    }\n    advance_until_leave!(tokens, tree, event_iter, RefNode::AnsiPortDeclaration);\n    port.type_str = clean_type_str(&tokens, &port.ident);\n    Some(port)\n}\n\npub fn list_port_idents(\n    tree: &SyntaxTree,\n    node: &ListOfPortIdentifiers,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut ports: Vec<PortDec> = Vec::new();\n    for port_def in node.nodes.0.contents() {\n        let mut port = PortDec::new(url);\n        let ident = get_ident(tree, RefNode::PortIdentifier(&port_def.0));\n        port.ident = ident.0;\n        port.byte_idx = ident.1;\n        for _ in &port_def.1 {\n            let tokens = &mut port.type_str;\n            advance_until_leave!(tokens, tree, event_iter, RefNode::UnpackedDimension);\n        }\n        ports.push(port);\n    }\n    Some(ports)\n}\n\npub fn list_interface_idents(\n    tree: &SyntaxTree,\n    node: &ListOfInterfaceIdentifiers,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut ports: Vec<PortDec> = Vec::new();\n    for port_def in node.nodes.0.contents() {\n        let mut port = PortDec::new(url);\n        let ident = get_ident(tree, RefNode::InterfaceIdentifier(&port_def.0));\n        port.ident = ident.0;\n        port.byte_idx = ident.1;\n        for _ in &port_def.1 {\n            let tokens = &mut port.type_str;\n            advance_until_leave!(tokens, tree, event_iter, RefNode::UnpackedDimension);\n        }\n        ports.push(port);\n    }\n    Some(ports)\n}\n\npub fn list_variable_idents(\n    tree: &SyntaxTree,\n    node: &ListOfVariableIdentifiers,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut ports: Vec<PortDec> = Vec::new();\n    for port_def in node.nodes.0.contents() {\n        let mut port = PortDec::new(url);\n        let ident = get_ident(tree, RefNode::VariableIdentifier(&port_def.0));\n        port.ident = ident.0;\n        port.byte_idx = ident.1;\n        for _ in &port_def.1 {\n            let tokens = &mut port.type_str;\n            advance_until_leave!(tokens, tree, event_iter, RefNode::VariableDimension);\n        }\n        ports.push(port);\n    }\n    Some(ports)\n}\n\npub fn port_dec_non_ansi(\n    tree: &SyntaxTree,\n    node: &PortDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut ports: Vec<PortDec>;\n    let mut common = String::new();\n    match node {\n        PortDeclaration::Inout(_) => {\n            let port_list = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::ListOfPortIdentifiers,\n                &ListOfPortIdentifiers\n            )?;\n            ports = list_port_idents(tree, port_list, event_iter, url)?;\n        }\n        PortDeclaration::Input(x) => match &x.nodes.1 {\n            InputDeclaration::Net(_) => {\n                let port_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfPortIdentifiers,\n                    &ListOfPortIdentifiers\n                )?;\n                ports = list_port_idents(tree, port_list, event_iter, url)?;\n            }\n            InputDeclaration::Variable(_) => {\n                let port_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfVariableIdentifiers,\n                    &ListOfVariableIdentifiers\n                )?;\n                ports = list_variable_idents(tree, port_list, event_iter, url)?;\n            }\n        },\n        PortDeclaration::Output(x) => match &x.nodes.1 {\n            OutputDeclaration::Net(_) => {\n                let port_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfPortIdentifiers,\n                    &ListOfPortIdentifiers\n                )?;\n                ports = list_port_idents(tree, port_list, event_iter, url)?;\n            }\n            OutputDeclaration::Variable(_) => {\n                let port_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfVariableIdentifiers,\n                    &ListOfVariableIdentifiers\n                )?;\n                ports = list_variable_idents(tree, port_list, event_iter, url)?;\n            }\n        },\n        PortDeclaration::Ref(_) => {\n            let port_list = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::ListOfVariableIdentifiers,\n                &ListOfVariableIdentifiers\n            )?;\n            ports = list_variable_idents(tree, port_list, event_iter, url)?;\n        }\n        PortDeclaration::Interface(x) => {\n            let interface =\n                Some(get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.1.nodes.0)).0);\n            let modport = x\n                .nodes\n                .1\n                .nodes\n                .1\n                .as_ref()\n                .map(|(_, mod_ident)| get_ident(tree, RefNode::ModportIdentifier(mod_ident)).0);\n            let port_list = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::ListOfInterfaceIdentifiers,\n                &ListOfInterfaceIdentifiers\n            )?;\n            ports = list_interface_idents(tree, port_list, event_iter, url)?;\n            for port in &mut ports {\n                port.interface = interface.clone();\n                port.modport = modport.clone();\n            }\n        }\n    }\n    for port in &mut ports {\n        port.type_str = format!(\"{} {}\", common, port.type_str);\n    }\n    Some(ports)\n}\n\npub fn list_net_decl(\n    tree: &SyntaxTree,\n    node: &ListOfNetDeclAssignments,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut nets: Vec<GenericDec> = Vec::new();\n    for net_def in node.nodes.0.contents() {\n        let mut net = GenericDec::new(url);\n        let ident = get_ident(tree, RefNode::NetIdentifier(&net_def.nodes.0));\n        net.ident = ident.0;\n        net.byte_idx = ident.1;\n        for _ in &net_def.nodes.1 {\n            let tokens = &mut net.type_str;\n            advance_until_leave!(tokens, tree, event_iter, RefNode::UnpackedDimension);\n        }\n        nets.push(net);\n    }\n    Some(nets)\n}\n\npub fn net_dec(\n    tree: &SyntaxTree,\n    node: &NetDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut nets: Vec<GenericDec>;\n    let mut common = String::new();\n    match node {\n        NetDeclaration::NetType(_) => {\n            let net_list = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::ListOfNetDeclAssignments,\n                &ListOfNetDeclAssignments\n            )?;\n            nets = list_net_decl(tree, net_list, event_iter, url)?;\n        }\n        NetDeclaration::NetTypeIdentifier(_) => {\n            let net_list = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::ListOfNetDeclAssignments,\n                &ListOfNetDeclAssignments\n            )?;\n            nets = list_net_decl(tree, net_list, event_iter, url)?;\n        }\n        NetDeclaration::Interconnect(x) => {\n            let mut net = GenericDec::new(url);\n            let ident = get_ident(tree, RefNode::NetIdentifier(&x.nodes.3));\n            net.ident = ident.0;\n            net.byte_idx = ident.1;\n            advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::NetIdentifier,\n                &NetIdentifier\n            );\n            for _ in &x.nodes.4 {\n                advance_until_leave!(common, tree, event_iter, RefNode::UnpackedDimension);\n            }\n            nets = vec![net];\n        }\n    }\n    for net in &mut nets {\n        net.completion_kind = CompletionItemKind::VARIABLE;\n        net.symbol_kind = SymbolKind::VARIABLE;\n        net.type_str = format!(\"{} {}\", common, net.type_str);\n    }\n    Some(nets)\n}\n\npub fn list_var_decl(\n    tree: &SyntaxTree,\n    node: &ListOfVariableDeclAssignments,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut vars: Vec<GenericDec> = Vec::new();\n    for var_def in node.nodes.0.contents() {\n        let mut var = GenericDec::new(url);\n        match &var_def {\n            VariableDeclAssignment::Variable(node) => {\n                let ident = get_ident(tree, RefNode::VariableIdentifier(&node.nodes.0));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n                for _ in &node.nodes.1 {\n                    let tokens = &mut var.type_str;\n                    advance_until_leave!(tokens, tree, event_iter, RefNode::VariableDimension);\n                }\n            }\n            VariableDeclAssignment::DynamicArray(node) => {\n                let ident = get_ident(tree, RefNode::DynamicArrayVariableIdentifier(&node.nodes.0));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n                for _ in &node.nodes.2 {\n                    let tokens = &mut var.type_str;\n                    advance_until_leave!(tokens, tree, event_iter, RefNode::VariableDimension);\n                }\n            }\n            VariableDeclAssignment::Class(node) => {\n                let ident = get_ident(tree, RefNode::ClassVariableIdentifier(&node.nodes.0));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n            }\n        }\n        vars.push(var);\n    }\n    Some(vars)\n}\n\npub fn package_import(\n    tree: &SyntaxTree,\n    node: &PackageImportDeclaration,\n    _: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PackageImport>> {\n    let mut imports = Vec::new();\n    for import_def in node.nodes.1.contents() {\n        let mut import = PackageImport::new(url);\n        match import_def {\n            PackageImportItem::Identifier(y) => {\n                let ident = get_ident(tree, RefNode::PackageIdentifier(&y.nodes.0));\n                import.ident = ident.0;\n                import.byte_idx = ident.1;\n                let import_loc = match &y.nodes.2 {\n                    Identifier::SimpleIdentifier(id) => id.nodes.0,\n                    Identifier::EscapedIdentifier(id) => id.nodes.0,\n                };\n                import.import_ident = Some(tree.get_str(&import_loc)?.to_string());\n            }\n            PackageImportItem::Asterisk(y) => {\n                let ident = get_ident(tree, RefNode::PackageIdentifier(&y.nodes.0));\n                import.ident = ident.0;\n                import.byte_idx = ident.1;\n                import.asterisk = true;\n            }\n        }\n        imports.push(import);\n    }\n    Some(imports)\n}\n\nfn struct_union(\n    tree: &SyntaxTree,\n    node: &DataTypeStructUnion,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope = GenericScope::new(url);\n    scope.start = get_loc(tree, RefNode::StructUnion(&node.nodes.0));\n    scope.end = get_loc(tree, RefNode::Symbol(&node.nodes.2.nodes.2));\n    scope.completion_kind = CompletionItemKind::STRUCT;\n    scope.symbol_kind = SymbolKind::STRUCT;\n    let type_str = &mut scope.type_str;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::Symbol)?;\n    let mut members = vec![&(node.nodes.2.nodes.1).0];\n    for member_def in &(node.nodes.2.nodes.1).1 {\n        members.push(member_def);\n    }\n    for member_def in members {\n        match member_def.nodes.2 {\n            DataTypeOrVoid::DataType(_) => {\n                let mut common = String::new();\n                let datatype =\n                    advance_until_enter!(common, tree, event_iter, RefNode::DataType, &DataType)?;\n                let dec = data_type(tree, datatype, event_iter, url)?;\n                match dec {\n                    Declaration::Dec(x) => {\n                        let var_list = advance_until_enter!(\n                            common,\n                            tree,\n                            event_iter,\n                            RefNode::ListOfVariableDeclAssignments,\n                            &ListOfVariableDeclAssignments\n                        )?;\n                        let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                        advance_until_leave!(common, tree, event_iter, RefNode::StructUnionMember);\n                        for var in &mut decs {\n                            var.type_str = format!(\"{} {} {}\", common, x.type_str, var.type_str);\n                            var.completion_kind = CompletionItemKind::VARIABLE;\n                            var.symbol_kind = SymbolKind::VARIABLE;\n                        }\n                        for var in decs {\n                            scope.defs.push(Box::new(var));\n                        }\n                    }\n                    Declaration::Scope(x) => {\n                        let var_list = advance_until_enter!(\n                            common,\n                            tree,\n                            event_iter,\n                            RefNode::ListOfVariableDeclAssignments,\n                            &ListOfVariableDeclAssignments\n                        )?;\n                        let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                        advance_until_leave!(common, tree, event_iter, RefNode::StructUnionMember);\n                        for var in &mut decs {\n                            var.type_str = format!(\"{} {} {}\", common, x.type_str, var.type_str);\n                            var.completion_kind = CompletionItemKind::VARIABLE;\n                            var.symbol_kind = SymbolKind::VARIABLE;\n                        }\n                        for var in decs {\n                            let mut member_scope = GenericScope::new(url);\n                            member_scope.start = x.start;\n                            member_scope.end = x.end;\n                            member_scope.defs = copy_defs(&x.defs);\n                            member_scope.scopes = copy_scopes(&x.scopes);\n                            member_scope.ident = var.ident;\n                            member_scope.byte_idx = var.byte_idx;\n                            scope.scopes.push(Box::new(member_scope));\n                        }\n                    }\n                    Declaration::Import(_) => {\n                        // datatype should not return import\n                        unreachable!()\n                    }\n                }\n            }\n            DataTypeOrVoid::Void(_) => {\n                let mut common = String::new();\n                let var_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfVariableDeclAssignments,\n                    &ListOfVariableDeclAssignments\n                )?;\n                let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                advance_until_leave!(common, tree, event_iter, RefNode::StructUnionMember);\n                for var in &mut decs {\n                    var.type_str = format!(\"{} {}\", common, var.type_str);\n                    var.completion_kind = CompletionItemKind::VARIABLE;\n                    var.symbol_kind = SymbolKind::VARIABLE;\n                }\n                for var in decs {\n                    scope.defs.push(Box::new(var));\n                }\n            }\n        }\n    }\n    skip_until_leave!(tree, event_iter, RefNode::DataTypeStructUnion);\n    Some(scope)\n}\n\npub enum Declaration {\n    Dec(GenericDec),\n    Scope(GenericScope),\n    Import(PackageImport),\n}\n\n// this isn't enough for a definition\nfn data_type(\n    tree: &SyntaxTree,\n    node: &DataType,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Declaration> {\n    let mut common = String::new();\n    match node {\n        DataType::Vector(_)\n        | DataType::Atom(_)\n        | DataType::NonIntegerType(_)\n        // TODO: set completion_kind and symbol_kind for string and others\n        | DataType::String(_)\n        | DataType::Chandle(_)\n        // TODO: properly handle the following types\n        | DataType::Virtual(_)\n        | DataType::Type(_)\n        | DataType::ClassType(_)\n        | DataType::Event(_)\n        | DataType::PsCovergroupIdentifier(_) => {\n            advance_until_leave!(common, tree, event_iter, RefNode::DataType)?;\n            let mut dec = GenericDec::new(url);\n            dec.type_str = common;\n            Some(Declaration::Dec(dec))\n        }\n        DataType::StructUnion(_) => {\n            let struct_union_def = advance_until_enter!(\n                common,\n                tree,\n                event_iter,\n                RefNode::DataTypeStructUnion,\n                &DataTypeStructUnion\n            )?;\n            let def = struct_union(\n                tree,\n                struct_union_def,\n                event_iter,\n                url,\n            )?;\n            advance_until_leave!(common, tree, event_iter, RefNode::DataType)?;\n            Some(Declaration::Scope(def))\n        }\n        DataType::Enum(node) => {\n            let mut scope = GenericScope::new(url);\n            scope.start = get_loc(tree, RefNode::Symbol(&node.nodes.2.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&node.nodes.2.nodes.2));\n            scope.completion_kind = CompletionItemKind::ENUM;\n            scope.symbol_kind = SymbolKind::ENUM;\n            let mut decs: Vec<GenericDec> = Vec::new();\n            for emem in node.nodes.2.nodes.1.contents() {\n                let mut dec = GenericDec::new(url);\n                let ident = get_ident(tree, RefNode::EnumIdentifier(&emem.nodes.0));\n                dec.ident = ident.0;\n                dec.byte_idx = ident.1;\n                dec.completion_kind = CompletionItemKind::ENUM_MEMBER;\n                dec.symbol_kind = SymbolKind::ENUM_MEMBER;\n                let tokens = &mut dec.type_str;\n                advance_until_leave!(tokens, tree, event_iter, RefNode::EnumNameDeclaration);\n                decs.push(dec);\n            }\n            advance_until_leave!(common, tree, event_iter, RefNode::DataType)?;\n            Some(Declaration::Scope(scope))\n        }\n        DataType::TypeReference(node) => {\n            match **node{\n                TypeReference::Expression(_) => {\n                    advance_until_leave!(common, tree, event_iter, RefNode::DataType)?;\n                    let mut dec = GenericDec::new(url);\n                    dec.type_str = common;\n                    Some(Declaration::Dec(dec))\n                }\n                TypeReference::DataType(_) => {\n                    let data_type_node = advance_until_enter!(common, tree, event_iter, RefNode::DataType, &DataType)?;\n                    let data_type_def = data_type(tree, data_type_node, event_iter, url);\n                    advance_until_leave!(common, tree, event_iter, RefNode::DataType)?;\n                    data_type_def\n                }\n            }\n        }\n    }\n}\n\npub fn data_dec(\n    tree: &SyntaxTree,\n    node: &DataDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<Declaration>> {\n    let mut common = String::new();\n    let mut data: Vec<Declaration> = Vec::new();\n    match node {\n        DataDeclaration::Variable(x) => match &x.nodes.3 {\n            DataTypeOrImplicit::DataType(_) => {\n                let mut common = String::new();\n                let datatype =\n                    advance_until_enter!(common, tree, event_iter, RefNode::DataType, &DataType)?;\n                let dec = data_type(tree, datatype, event_iter, url)?;\n                match dec {\n                    Declaration::Dec(x) => {\n                        let var_list = advance_until_enter!(\n                            common,\n                            tree,\n                            event_iter,\n                            RefNode::ListOfVariableDeclAssignments,\n                            &ListOfVariableDeclAssignments\n                        )?;\n                        let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                        for var in &mut decs {\n                            var.type_str = format!(\"{} {} {}\", common, x.type_str, var.type_str);\n                            var.completion_kind = CompletionItemKind::VARIABLE;\n                            var.symbol_kind = SymbolKind::VARIABLE;\n                        }\n                        for var in decs {\n                            data.push(Declaration::Dec(var));\n                        }\n                    }\n                    Declaration::Scope(x) => {\n                        let var_list = advance_until_enter!(\n                            common,\n                            tree,\n                            event_iter,\n                            RefNode::ListOfVariableDeclAssignments,\n                            &ListOfVariableDeclAssignments\n                        )?;\n                        let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                        for var in &mut decs {\n                            var.type_str = format!(\"{} {} {}\", common, x.type_str, var.type_str);\n                            var.completion_kind = CompletionItemKind::VARIABLE;\n                            var.symbol_kind = SymbolKind::VARIABLE;\n                        }\n                        for var in decs {\n                            data.push(Declaration::Scope(GenericScope {\n                                ident: var.ident,\n                                byte_idx: var.byte_idx,\n                                start: x.start,\n                                end: x.end,\n                                url: url.clone(),\n                                type_str: var.type_str,\n                                completion_kind: x.completion_kind,\n                                symbol_kind: x.symbol_kind,\n                                def_type: x.def_type,\n                                defs: copy_defs(&x.defs),\n                                scopes: copy_scopes(&x.scopes),\n                            }));\n                        }\n                    }\n                    Declaration::Import(_) => {\n                        // datatype should not return import\n                        unreachable!()\n                    }\n                }\n            }\n            DataTypeOrImplicit::ImplicitDataType(_) => {\n                let var_list = advance_until_enter!(\n                    common,\n                    tree,\n                    event_iter,\n                    RefNode::ListOfVariableDeclAssignments,\n                    &ListOfVariableDeclAssignments\n                )?;\n                let mut decs = list_var_decl(tree, var_list, event_iter, url)?;\n                data = Vec::new();\n                for var in &mut decs {\n                    var.type_str = format!(\"{} {}\", common, var.type_str);\n                    var.completion_kind = CompletionItemKind::VARIABLE;\n                    var.symbol_kind = SymbolKind::VARIABLE;\n                }\n                for var in decs {\n                    data.push(Declaration::Dec(var));\n                }\n            }\n        },\n        DataDeclaration::TypeDeclaration(x) => match &**x {\n            TypeDeclaration::DataType(y) => {\n                let mut common = String::new();\n                let datatype =\n                    advance_until_enter!(common, tree, event_iter, RefNode::DataType, &DataType)?;\n                let dec = data_type(tree, datatype, event_iter, url)?;\n                match dec {\n                    Declaration::Dec(mut def) => {\n                        let ident = get_ident(tree, RefNode::TypeIdentifier(&y.nodes.2));\n                        def.ident = ident.0;\n                        def.byte_idx = ident.1;\n                        for _ in &y.nodes.3 {\n                            let tokens = &mut def.type_str;\n                            advance_until_leave!(\n                                tokens,\n                                tree,\n                                event_iter,\n                                RefNode::VariableDimension\n                            );\n                        }\n                        def.type_str = format!(\"{} {}\", common, def.type_str);\n                        data = vec![Declaration::Dec(def)];\n                    }\n                    Declaration::Scope(mut def) => {\n                        let ident = get_ident(tree, RefNode::TypeIdentifier(&y.nodes.2));\n                        def.ident = ident.0;\n                        def.byte_idx = ident.1;\n                        for _ in &y.nodes.3 {\n                            let tokens = &mut def.type_str;\n                            advance_until_leave!(\n                                tokens,\n                                tree,\n                                event_iter,\n                                RefNode::VariableDimension\n                            );\n                        }\n                        def.type_str = format!(\"{} {}\", common, def.type_str);\n                        data = vec![Declaration::Scope(def)];\n                    }\n                    Declaration::Import(_) => unreachable!(),\n                }\n            }\n            TypeDeclaration::Interface(y) => {\n                let mut var = GenericDec::new(url);\n                let ident = get_ident(tree, RefNode::TypeIdentifier(&y.nodes.5));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n                let mut tokens = String::new();\n                advance_until_enter!(\n                    tokens,\n                    tree,\n                    event_iter,\n                    RefNode::TypeIdentifier,\n                    &TypeIdentifier\n                );\n                advance_until_enter!(\n                    tokens,\n                    tree,\n                    event_iter,\n                    RefNode::TypeIdentifier,\n                    &TypeIdentifier\n                );\n                var.type_str = tokens;\n                var.type_str = format!(\"{} {}\", common, var.type_str);\n                var.completion_kind = CompletionItemKind::INTERFACE;\n                var.symbol_kind = SymbolKind::INTERFACE;\n                data = vec![Declaration::Dec(var)];\n            }\n            TypeDeclaration::Reserved(y) => {\n                let mut var = GenericDec::new(url);\n                let ident = get_ident(tree, RefNode::TypeIdentifier(&y.nodes.2));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n                let mut tokens = String::new();\n                advance_until_enter!(\n                    tokens,\n                    tree,\n                    event_iter,\n                    RefNode::TypeIdentifier,\n                    &TypeIdentifier\n                );\n                var.type_str = tokens;\n                var.type_str = format!(\"{} {}\", common, var.type_str);\n                var.completion_kind = CompletionItemKind::VARIABLE;\n                var.symbol_kind = SymbolKind::VARIABLE;\n                data = vec![Declaration::Dec(var)];\n            }\n        },\n        DataDeclaration::PackageImportDeclaration(x) => {\n            data = Vec::new();\n            let imports = package_import(tree, x, event_iter, url)?;\n            for import in imports {\n                data.push(Declaration::Import(import));\n            }\n        }\n        DataDeclaration::NetTypeDeclaration(x) => match &**x {\n            NetTypeDeclaration::DataType(y) => {\n                let mut common = String::new();\n                let datatype =\n                    advance_until_enter!(common, tree, event_iter, RefNode::DataType, &DataType)?;\n                let dec = data_type(tree, datatype, event_iter, url)?;\n                match dec {\n                    Declaration::Dec(mut def) => {\n                        let ident = get_ident(tree, RefNode::NetTypeIdentifier(&y.nodes.2));\n                        def.ident = ident.0;\n                        def.byte_idx = ident.1;\n                        let mut tokens = String::new();\n                        advance_until_enter!(\n                            tokens,\n                            tree,\n                            event_iter,\n                            RefNode::NetTypeIdentifier,\n                            &NetTypeIdentifier\n                        );\n                        def.type_str = tokens;\n                        def.type_str = format!(\"{} {}\", common, def.type_str);\n                        data = vec![Declaration::Dec(def)];\n                    }\n                    Declaration::Scope(mut def) => {\n                        let ident = get_ident(tree, RefNode::NetTypeIdentifier(&y.nodes.2));\n                        def.ident = ident.0;\n                        def.byte_idx = ident.1;\n                        let mut tokens = String::new();\n                        advance_until_enter!(\n                            tokens,\n                            tree,\n                            event_iter,\n                            RefNode::NetTypeIdentifier,\n                            &NetTypeIdentifier\n                        );\n                        def.type_str = tokens;\n                        def.type_str = format!(\"{} {}\", common, def.type_str);\n                        data = vec![Declaration::Scope(def)];\n                    }\n                    Declaration::Import(_) => unreachable!(),\n                }\n            }\n            NetTypeDeclaration::NetType(y) => {\n                let mut var = GenericDec::new(url);\n                let ident = get_ident(tree, RefNode::NetTypeIdentifier(&y.nodes.2));\n                var.ident = ident.0;\n                var.byte_idx = ident.1;\n                let mut tokens = String::new();\n                advance_until_leave!(tokens, tree, event_iter, RefNode::NetTypeIdentifier);\n                var.type_str = tokens;\n                var.type_str = format!(\"{} {}\", common, var.type_str);\n                var.completion_kind = CompletionItemKind::VARIABLE;\n                var.symbol_kind = SymbolKind::VARIABLE;\n                data = vec![Declaration::Dec(var)];\n            }\n        },\n    }\n    Some(data)\n}\n\npub fn tfport_list(\n    tree: &SyntaxTree,\n    node: &TfPortList,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut tfports: Vec<PortDec> = Vec::new();\n    for tfports_def in node.nodes.0.contents() {\n        if let Some(def) = &tfports_def.nodes.4 {\n            let mut tfport = PortDec::new(url);\n            let ident = get_ident(tree, RefNode::PortIdentifier(&def.0));\n            tfport.ident = ident.0;\n            tfport.byte_idx = ident.1;\n            for _ in &def.1 {\n                let tokens = &mut tfport.type_str;\n                advance_until_leave!(tokens, tree, event_iter, RefNode::UnpackedDimension);\n            }\n            tfports.push(tfport);\n        }\n    }\n    Some(tfports)\n}\n\npub fn function_dec(\n    tree: &SyntaxTree,\n    node: &FunctionDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<SubDec> {\n    let mut func: SubDec = SubDec::new(url);\n    func.start = get_loc(tree, RefNode::Keyword(&node.nodes.0));\n    match &node.nodes.2 {\n        FunctionBodyDeclaration::WithoutPort(x) => {\n            func.end = get_loc(tree, RefNode::Keyword(&x.nodes.6));\n            let ident = get_ident(tree, RefNode::FunctionIdentifier(&x.nodes.2));\n            func.ident = ident.0;\n            func.byte_idx = ident.1;\n            let mut tokens = String::new();\n            advance_until_enter!(\n                tokens,\n                tree,\n                event_iter,\n                RefNode::FunctionIdentifier,\n                &FunctionIdentifier\n            );\n            func.type_str = tokens;\n        }\n        FunctionBodyDeclaration::WithPort(x) => {\n            func.end = get_loc(tree, RefNode::Keyword(&x.nodes.7));\n            let ident = get_ident(tree, RefNode::FunctionIdentifier(&x.nodes.2));\n            func.ident = ident.0;\n            func.byte_idx = ident.1;\n            let mut tokens = String::new();\n            advance_until_enter!(\n                tokens,\n                tree,\n                event_iter,\n                RefNode::FunctionIdentifier,\n                &FunctionIdentifier\n            );\n            func.type_str = tokens;\n            if let Some(tfports) = &x.nodes.3.nodes.1 {\n                skip_until_enter!(tree, event_iter, RefNode::TfPortList, &TfPortList);\n                let ports = tfport_list(tree, tfports, event_iter, url)?;\n                for port in ports {\n                    func.defs.push(Box::new(port));\n                }\n            }\n        }\n    }\n    let (scopes, mut defs) =\n        match_until_leave!(tree, event_iter, url, RefNode::FunctionDeclaration)?;\n    func.scopes = scopes;\n    func.defs.append(&mut defs);\n    Some(func)\n}\n\npub fn task_dec(\n    tree: &SyntaxTree,\n    node: &TaskDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<SubDec> {\n    let mut task = SubDec::new(url);\n    task.start = get_loc(tree, RefNode::Keyword(&node.nodes.0));\n    match &node.nodes.2 {\n        TaskBodyDeclaration::WithoutPort(x) => {\n            task.end = get_loc(tree, RefNode::Keyword(&x.nodes.5));\n            let ident = get_ident(tree, RefNode::TaskIdentifier(&x.nodes.1));\n            task.ident = ident.0;\n            task.byte_idx = ident.1;\n            let mut tokens = String::new();\n            advance_until_enter!(\n                tokens,\n                tree,\n                event_iter,\n                RefNode::TaskIdentifier,\n                &TaskIdentifier\n            );\n            task.type_str = tokens;\n        }\n        TaskBodyDeclaration::WithPort(x) => {\n            task.end = get_loc(tree, RefNode::Keyword(&x.nodes.6));\n            let mut task = SubDec::new(url);\n            let ident = get_ident(tree, RefNode::TaskIdentifier(&x.nodes.1));\n            task.ident = ident.0;\n            task.byte_idx = ident.1;\n            let mut tokens = String::new();\n            advance_until_enter!(\n                tokens,\n                tree,\n                event_iter,\n                RefNode::TaskIdentifier,\n                &TaskIdentifier\n            );\n            task.type_str = tokens;\n            if let Some(tfports) = &x.nodes.2.nodes.1 {\n                skip_until_enter!(tree, event_iter, RefNode::TfPortList, &TfPortList);\n                let ports = tfport_list(tree, tfports, event_iter, url)?;\n                for port in ports {\n                    task.defs.push(Box::new(port));\n                }\n            }\n        }\n    }\n    let (scopes, mut defs) = match_until_leave!(tree, event_iter, url, RefNode::TaskDeclaration)?;\n    task.scopes = scopes;\n    task.defs.append(&mut defs);\n    Some(task)\n}\n\npub fn modport_dec(\n    tree: &SyntaxTree,\n    node: &ModportDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<ModportDec>> {\n    let mut modports: Vec<ModportDec> = Vec::new();\n    let mut common = String::new();\n    advance_until_enter!(common, tree, event_iter, RefNode::ModportItem, &ModportItem);\n    for modport_def in node.nodes.1.contents() {\n        let mut modport = ModportDec::new(url);\n        let ident = get_ident(tree, RefNode::ModportIdentifier(&modport_def.nodes.0));\n        modport.ident = ident.0;\n        modport.byte_idx = ident.1;\n        modport.type_str = common.clone();\n\n        for mp_port_dec in modport_def.nodes.1.nodes.1.contents() {\n            match mp_port_dec {\n                ModportPortsDeclaration::Simple(x) => {\n                    skip_until_enter!(\n                        tree,\n                        event_iter,\n                        RefNode::ModportPortsDeclarationSimple,\n                        &ModportPortsDeclarationSimple\n                    );\n                    let mut prepend = String::new();\n                    advance_until_enter!(\n                        prepend,\n                        tree,\n                        event_iter,\n                        RefNode::ModportSimplePort,\n                        &ModportSimplePort\n                    );\n                    for mp_simple_def in x.nodes.1.nodes.1.contents() {\n                        match mp_simple_def {\n                            ModportSimplePort::Ordered(y) => {\n                                let mut port = PortDec::new(url);\n                                let ident = get_ident(tree, RefNode::PortIdentifier(&y.nodes.0));\n                                port.ident = ident.0;\n                                port.byte_idx = ident.1;\n                                port.type_str = prepend.clone();\n                                modport.ports.push(Box::new(port));\n                            }\n                            ModportSimplePort::Named(_) => {\n                                let port_ident = skip_until_enter!(\n                                    tree,\n                                    event_iter,\n                                    RefNode::PortIdentifier,\n                                    &PortIdentifier\n                                )?;\n                                let mut port = PortDec::new(url);\n                                let ident = get_ident(tree, RefNode::PortIdentifier(port_ident));\n                                port.ident = ident.0;\n                                port.byte_idx = ident.1;\n                                let mut append = String::new();\n                                advance_until_leave!(\n                                    append,\n                                    tree,\n                                    event_iter,\n                                    RefNode::ModportSimplePortNamed\n                                );\n                                port.type_str = format!(\"{} {}\", prepend, append);\n                                modport.ports.push(Box::new(port));\n                            }\n                        }\n                    }\n                }\n                ModportPortsDeclaration::Tf(_) => {\n                    skip_until_enter!(\n                        tree,\n                        event_iter,\n                        RefNode::ModportPortsDeclarationTf,\n                        &ModportPortsDeclarationTf\n                    );\n                    let mut prepend = String::new();\n                    let mp_tf_ports_dec = advance_until_enter!(\n                        prepend,\n                        tree,\n                        event_iter,\n                        RefNode::ModportTfPortsDeclaration,\n                        &ModportTfPortsDeclaration\n                    )?;\n                    for mp_tf_port in mp_tf_ports_dec.nodes.1.contents() {\n                        match mp_tf_port {\n                            ModportTfPort::MethodPrototype(y) => match &**y {\n                                MethodPrototype::TaskPrototype(z) => {\n                                    let mut port = SubDec::new(url);\n                                    let ident =\n                                        get_ident(tree, RefNode::TaskIdentifier(&z.nodes.1));\n                                    port.ident = ident.0;\n                                    port.byte_idx = ident.1;\n                                    skip_until_enter!(\n                                        tree,\n                                        event_iter,\n                                        RefNode::TaskPrototype,\n                                        &TaskPrototype\n                                    );\n                                    let tokens = &mut port.type_str;\n                                    advance_until_leave!(\n                                        tokens,\n                                        tree,\n                                        event_iter,\n                                        RefNode::TaskPrototype\n                                    );\n                                    modport.ports.push(Box::new(port));\n                                }\n                                MethodPrototype::FunctionPrototype(z) => {\n                                    let mut port = SubDec::new(url);\n                                    let ident =\n                                        get_ident(tree, RefNode::FunctionIdentifier(&z.nodes.2));\n                                    port.ident = ident.0;\n                                    port.byte_idx = ident.1;\n                                    skip_until_enter!(\n                                        tree,\n                                        event_iter,\n                                        RefNode::FunctionPrototype,\n                                        &FunctionPrototype\n                                    );\n                                    let tokens = &mut port.type_str;\n                                    advance_until_leave!(\n                                        tokens,\n                                        tree,\n                                        event_iter,\n                                        RefNode::FunctionIdentifier\n                                    );\n                                    modport.ports.push(Box::new(port));\n                                }\n                            },\n                            ModportTfPort::TfIdentifier(y) => {\n                                let mut port = SubDec::new(url);\n                                let ident = get_ident(tree, RefNode::TfIdentifier(y));\n                                port.ident = ident.0;\n                                port.byte_idx = ident.1;\n                                port.type_str = prepend.clone();\n                                modport.ports.push(Box::new(port));\n                            }\n                        }\n                    }\n                }\n                ModportPortsDeclaration::Clocking(_) => {\n                    skip_until_enter!(\n                        tree,\n                        event_iter,\n                        RefNode::ModportPortsDeclarationClocking,\n                        &ModportPortsDeclarationClocking\n                    );\n                    let mut tokens = String::new();\n                    let clock_ident = advance_until_enter!(\n                        tokens,\n                        tree,\n                        event_iter,\n                        RefNode::ClockingIdentifier,\n                        &ClockingIdentifier\n                    )?;\n                    let ident = get_ident(tree, RefNode::ClockingIdentifier(clock_ident));\n                    let mut port = PortDec::new(url);\n                    port.ident = ident.0;\n                    port.byte_idx = ident.1;\n                    port.type_str = tokens;\n                    modport.ports.push(Box::new(port));\n                }\n            }\n        }\n\n        modports.push(modport);\n    }\n    Some(modports)\n}\n\npub fn module_inst(\n    tree: &SyntaxTree,\n    node: &ModuleInstantiation,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<ModInst>> {\n    let mut defs: Vec<ModInst> = Vec::new();\n    let mod_ident = get_ident(tree, RefNode::ModuleIdentifier(&node.nodes.0)).0;\n    for _ in node.nodes.2.contents() {\n        let hinst = skip_until_enter!(\n            tree,\n            event_iter,\n            RefNode::HierarchicalInstance,\n            &HierarchicalInstance\n        )?;\n        let mut instance = ModInst::new(url);\n        let ident = get_ident(tree, RefNode::InstanceIdentifier(&hinst.nodes.0.nodes.0));\n        instance.ident = ident.0;\n        instance.byte_idx = ident.1;\n        instance.type_str = mod_ident.clone();\n        instance.mod_ident = mod_ident.clone();\n        let type_str = &mut instance.type_str;\n        for _ in &hinst.nodes.0.nodes.1 {\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UnpackedDimension);\n        }\n        defs.push(instance);\n    }\n    Some(defs)\n}\n\nfn param_assignment(\n    tree: &SyntaxTree,\n    _: &ParamAssignment,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericDec> {\n    let param_assign =\n        skip_until_enter!(tree, event_iter, RefNode::ParamAssignment, &ParamAssignment)?;\n    let mut def = GenericDec::new(url);\n    let ident = get_ident(tree, RefNode::ParameterIdentifier(&param_assign.nodes.0));\n    def.ident = ident.0;\n    def.byte_idx = ident.1;\n    let type_str = &mut def.type_str;\n    def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n    def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::ParamAssignment);\n    Some(def)\n}\n\nfn list_param_assignment(\n    tree: &SyntaxTree,\n    _: &ListOfParamAssignments,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut defs: Vec<GenericDec> = Vec::new();\n    let p_a_list = skip_until_enter!(\n        tree,\n        event_iter,\n        RefNode::ListOfParamAssignments,\n        &ListOfParamAssignments\n    )?;\n    for param_assign in p_a_list.nodes.0.contents() {\n        defs.push(param_assignment(tree, param_assign, event_iter, url)?);\n    }\n    Some(defs)\n}\n\nfn type_assignment(\n    tree: &SyntaxTree,\n    _: &TypeAssignment,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericDec> {\n    let type_assign =\n        skip_until_enter!(tree, event_iter, RefNode::TypeAssignment, &TypeAssignment)?;\n    let mut def = GenericDec::new(url);\n    let ident = get_ident(tree, RefNode::TypeIdentifier(&type_assign.nodes.0));\n    def.ident = ident.0;\n    def.byte_idx = ident.1;\n    def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n    def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n    let type_str = &mut def.type_str;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::TypeAssignment);\n    Some(def)\n}\n\nfn list_type_assignment(\n    tree: &SyntaxTree,\n    _: &ListOfTypeAssignments,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut defs: Vec<GenericDec> = Vec::new();\n    let p_a_list = skip_until_enter!(\n        tree,\n        event_iter,\n        RefNode::ListOfTypeAssignments,\n        &ListOfTypeAssignments\n    )?;\n    for type_assign in p_a_list.nodes.0.contents() {\n        defs.push(type_assignment(tree, type_assign, event_iter, url)?);\n    }\n    Some(defs)\n}\n\npub fn param_dec(\n    tree: &SyntaxTree,\n    param_dec: &ParameterDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    match param_dec {\n        ParameterDeclaration::Param(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::DataTypeOrImplicit);\n            let mut defs = list_param_assignment(tree, &x.nodes.2, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n        ParameterDeclaration::Type(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::Keyword);\n            advance_until_leave!(prepend, tree, event_iter, RefNode::Keyword);\n            let mut defs = list_type_assignment(tree, &x.nodes.2, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n    }\n}\n\npub fn localparam_dec(\n    tree: &SyntaxTree,\n    localparam_dec: &LocalParameterDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    match localparam_dec {\n        LocalParameterDeclaration::Param(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::DataTypeOrImplicit);\n            let mut defs = list_param_assignment(tree, &x.nodes.2, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n        LocalParameterDeclaration::Type(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::Keyword);\n            advance_until_leave!(prepend, tree, event_iter, RefNode::Keyword);\n            let mut defs = list_type_assignment(tree, &x.nodes.2, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n    }\n}\n\nfn param_port_dec(\n    tree: &SyntaxTree,\n    node: &ParameterPortDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    match node {\n        ParameterPortDeclaration::ParameterDeclaration(_) => {\n            let param = skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::ParameterDeclaration,\n                &ParameterDeclaration\n            )?;\n            param_dec(tree, param, event_iter, url)\n        }\n        ParameterPortDeclaration::LocalParameterDeclaration(_) => {\n            let localparam = skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::LocalParameterDeclaration,\n                &LocalParameterDeclaration\n            )?;\n            localparam_dec(tree, localparam, event_iter, url)\n        }\n        ParameterPortDeclaration::ParamList(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::DataType);\n            let mut defs = list_param_assignment(tree, &x.nodes.1, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n        ParameterPortDeclaration::TypeList(x) => {\n            let mut prepend = String::new();\n            advance_until_leave!(prepend, tree, event_iter, RefNode::Keyword);\n            let mut defs = list_type_assignment(tree, &x.nodes.1, event_iter, url)?;\n            for def in &mut defs {\n                def.type_str = format!(\"{} {}\", prepend, def.type_str);\n                def.completion_kind = CompletionItemKind::TYPE_PARAMETER;\n                def.symbol_kind = SymbolKind::TYPE_PARAMETER;\n            }\n            Some(defs)\n        }\n    }\n}\n\npub fn param_port_list(\n    tree: &SyntaxTree,\n    node: &ParameterPortList,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<GenericDec>> {\n    let mut defs: Vec<GenericDec> = Vec::new();\n    match node {\n        ParameterPortList::Assignment(x) => {\n            defs.append(&mut list_param_assignment(\n                tree,\n                &(x.nodes.1.nodes.1).0,\n                event_iter,\n                url,\n            )?);\n            for port_dec in &(x.nodes.1.nodes.1).1 {\n                defs.append(&mut param_port_dec(tree, &port_dec.1, event_iter, url)?);\n            }\n        }\n        ParameterPortList::Declaration(x) => {\n            let mut param_port_decs = vec![&x.nodes.1.nodes.1.nodes.0];\n            for param_port_dec in &x.nodes.1.nodes.1.nodes.1 {\n                param_port_decs.push(&param_port_dec.1);\n            }\n            for port_dec in param_port_decs {\n                defs.append(&mut param_port_dec(tree, port_dec, event_iter, url)?);\n            }\n        }\n        ParameterPortList::Empty(_) => {}\n    }\n    Some(defs)\n}\n\npub fn module_dec(\n    tree: &SyntaxTree,\n    node: &ModuleDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    match node {\n        ModuleDeclaration::Nonansi(x) => {\n            scope.start = get_loc(tree, RefNode::ModuleKeyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::ModuleIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ModuleIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n        ModuleDeclaration::Ansi(x) => {\n            scope.start = get_loc(tree, RefNode::ModuleKeyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::ModuleIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ModuleIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.0.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    let mut prev_type_str = String::new();\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        // propogate type str for multi-port declaration\n                        let mut port_dec = port_dec_ansi(tree, ansi_dec, event_iter, url)?;\n                        if port_dec.type_str.is_empty() && !prev_type_str.is_empty() {\n                            port_dec.type_str = prev_type_str.clone();\n                        } else {\n                            prev_type_str = port_dec.type_str.clone();\n                        }\n                        scope.defs.push(Box::new(port_dec))\n                    }\n                }\n            }\n        }\n        ModuleDeclaration::Wildcard(x) => {\n            scope.start = get_loc(tree, RefNode::ModuleKeyword(&x.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.8));\n            let ident = get_ident(tree, RefNode::ModuleIdentifier(&x.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ModuleIdentifier);\n        }\n        ModuleDeclaration::ExternNonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::ModuleIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ModuleIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n        ModuleDeclaration::ExternAnsi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::ModuleIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ModuleIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.1.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        scope\n                            .defs\n                            .push(Box::new(port_dec_ansi(tree, ansi_dec, event_iter, url)?))\n                    }\n                }\n            }\n        }\n    }\n    let (scopes, mut defs) = match_until_leave!(tree, event_iter, url, RefNode::ModuleDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::MODULE;\n    scope.symbol_kind = SymbolKind::MODULE;\n    Some(scope)\n}\n\npub fn interface_dec(\n    tree: &SyntaxTree,\n    node: &InterfaceDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    match node {\n        InterfaceDeclaration::Nonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n        InterfaceDeclaration::Ansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.0.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        scope\n                            .defs\n                            .push(Box::new(port_dec_ansi(tree, ansi_dec, event_iter, url)?))\n                    }\n                }\n            }\n        }\n        InterfaceDeclaration::Wildcard(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.8));\n            let ident = get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n        }\n        InterfaceDeclaration::ExternNonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n        InterfaceDeclaration::ExternAnsi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::InterfaceIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.1.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        scope\n                            .defs\n                            .push(Box::new(port_dec_ansi(tree, ansi_dec, event_iter, url)?))\n                    }\n                }\n            }\n        }\n    }\n    let (scopes, mut defs) =\n        match_until_leave!(tree, event_iter, url, RefNode::InterfaceDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::INTERFACE;\n    scope.symbol_kind = SymbolKind::INTERFACE;\n    Some(scope)\n}\n\nfn list_udp_port_idents(\n    tree: &SyntaxTree,\n    node: &ListOfUdpPortIdentifiers,\n    _: &mut EventIter,\n    url: &Url,\n) -> Vec<PortDec> {\n    let mut ports: Vec<PortDec> = Vec::new();\n    for port_def in node.nodes.0.contents() {\n        let mut port = PortDec::new(url);\n        let ident = get_ident(tree, RefNode::PortIdentifier(port_def));\n        port.ident = ident.0;\n        port.byte_idx = ident.1;\n        ports.push(port);\n    }\n    ports\n}\n\n//non-ansi udp ports\nfn udp_port_dec(\n    tree: &SyntaxTree,\n    node: &UdpPortDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    match node {\n        UdpPortDeclaration::UdpOutputDeclaration(x) => match &x.0 {\n            UdpOutputDeclaration::Nonreg(x) => {\n                let mut port = PortDec::new(url);\n                let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.2));\n                port.ident = ident.0;\n                port.byte_idx = ident.1;\n                skip_until_enter!(\n                    tree,\n                    event_iter,\n                    RefNode::UdpOutputDeclarationNonreg,\n                    &UdpOutputDeclarationNonreg\n                );\n                let type_str = &mut port.type_str;\n                advance_until_leave!(\n                    type_str,\n                    tree,\n                    event_iter,\n                    RefNode::UdpOutputDeclarationNonreg\n                );\n                Some(vec![port])\n            }\n            UdpOutputDeclaration::Reg(x) => {\n                let mut port = PortDec::new(url);\n                let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.3));\n                port.ident = ident.0;\n                port.byte_idx = ident.1;\n                skip_until_enter!(\n                    tree,\n                    event_iter,\n                    RefNode::UdpOutputDeclarationReg,\n                    &UdpOutputDeclarationReg\n                );\n                let type_str = &mut port.type_str;\n                advance_until_leave!(type_str, tree, event_iter, RefNode::UdpOutputDeclarationReg);\n                Some(vec![port])\n            }\n        },\n        UdpPortDeclaration::UdpInputDeclaration(_) => {\n            skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::UdpInputDeclaration,\n                &UdpInputDeclaration\n            );\n            let mut type_str = String::new();\n            let list_udp_ports = advance_until_enter!(\n                type_str,\n                tree,\n                event_iter,\n                RefNode::ListOfUdpPortIdentifiers,\n                &ListOfUdpPortIdentifiers\n            )?;\n            let mut ports = list_udp_port_idents(tree, list_udp_ports, event_iter, url);\n            for port in &mut ports {\n                port.type_str = type_str.clone();\n            }\n            Some(ports)\n        }\n        UdpPortDeclaration::UdpRegDeclaration(_) => {\n            let udp_reg_dec = skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::UdpRegDeclaration,\n                &UdpRegDeclaration\n            )?;\n            let mut port = PortDec::new(url);\n            let type_str = &mut port.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::Keyword);\n            let ident = get_ident(tree, RefNode::VariableIdentifier(&udp_reg_dec.nodes.2));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n            Some(vec![port])\n        }\n    }\n}\n\n//ansi udp ports\nfn udp_port_list(\n    tree: &SyntaxTree,\n    node: &UdpDeclarationPortList,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<Vec<PortDec>> {\n    let mut ports: Vec<PortDec> = Vec::new();\n    match &node.nodes.0 {\n        UdpOutputDeclaration::Nonreg(x) => {\n            let mut port = PortDec::new(url);\n            let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.2));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n            skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::UdpOutputDeclarationNonreg,\n                &UdpOutputDeclarationNonreg\n            );\n            let type_str = &mut port.type_str;\n            advance_until_leave!(\n                type_str,\n                tree,\n                event_iter,\n                RefNode::UdpOutputDeclarationNonreg\n            );\n            ports.push(port);\n        }\n        UdpOutputDeclaration::Reg(x) => {\n            let mut port = PortDec::new(url);\n            let ident = get_ident(tree, RefNode::PortIdentifier(&x.nodes.3));\n            port.ident = ident.0;\n            port.byte_idx = ident.1;\n            skip_until_enter!(\n                tree,\n                event_iter,\n                RefNode::UdpOutputDeclarationReg,\n                &UdpOutputDeclarationReg\n            );\n            let type_str = &mut port.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpOutputDeclarationReg);\n            ports.push(port);\n        }\n    }\n    for _port_def in node.nodes.2.contents() {\n        skip_until_enter!(\n            tree,\n            event_iter,\n            RefNode::UdpInputDeclaration,\n            &UdpInputDeclaration\n        );\n        let mut type_str = String::new();\n        let list_udp_ports = advance_until_enter!(\n            type_str,\n            tree,\n            event_iter,\n            RefNode::ListOfUdpPortIdentifiers,\n            &ListOfUdpPortIdentifiers\n        )?;\n        let mut port_decs = list_udp_port_idents(tree, list_udp_ports, event_iter, url);\n        for port in &mut port_decs {\n            port.type_str = type_str.clone();\n        }\n        ports.append(&mut port_decs);\n    }\n    Some(ports)\n}\n\npub fn udp_dec(\n    tree: &SyntaxTree,\n    node: &UdpDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    match node {\n        UdpDeclaration::Nonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.4));\n            let ident = get_ident(tree, RefNode::UdpIdentifier(&x.nodes.0.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpIdentifier);\n            let mut port_decs = vec![&x.nodes.1];\n            for port_dec in &x.nodes.2 {\n                port_decs.push(port_dec);\n            }\n            for port in port_decs {\n                let ports = udp_port_dec(tree, port, event_iter, url)?;\n                for port_dec in ports {\n                    scope.defs.push(Box::new(port_dec));\n                }\n            }\n        }\n        UdpDeclaration::Ansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.2));\n            let ident = get_ident(tree, RefNode::UdpIdentifier(&x.nodes.0.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpIdentifier);\n            let ports = udp_port_list(tree, &x.nodes.0.nodes.3.nodes.1, event_iter, url)?;\n            for port_dec in ports {\n                scope.defs.push(Box::new(port_dec));\n            }\n        }\n        UdpDeclaration::ExternNonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.4));\n            let ident = get_ident(tree, RefNode::UdpIdentifier(&x.nodes.1.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpIdentifier);\n        }\n        UdpDeclaration::ExternAnsi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.4));\n            let ident = get_ident(tree, RefNode::UdpIdentifier(&x.nodes.1.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpIdentifier);\n            let ports = udp_port_list(tree, &x.nodes.1.nodes.3.nodes.1, event_iter, url)?;\n            for port_dec in ports {\n                scope.defs.push(Box::new(port_dec));\n            }\n        }\n        UdpDeclaration::Wildcard(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.7));\n            let ident = get_ident(tree, RefNode::UdpIdentifier(&x.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::UdpIdentifier);\n            for port_dec in &x.nodes.5 {\n                let ports = udp_port_dec(tree, port_dec, event_iter, url)?;\n                for port in ports {\n                    scope.defs.push(Box::new(port));\n                }\n            }\n        }\n    }\n\n    let (scopes, mut defs) = match_until_leave!(tree, event_iter, url, RefNode::UdpDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::MODULE;\n    scope.symbol_kind = SymbolKind::MODULE;\n    Some(scope)\n}\n\npub fn program_dec(\n    tree: &SyntaxTree,\n    node: &ProgramDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    match node {\n        ProgramDeclaration::Nonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::ProgramIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::InterfaceIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n\n        ProgramDeclaration::Ansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.3));\n            let ident = get_ident(tree, RefNode::ProgramIdentifier(&x.nodes.0.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ProgramIdentifier);\n            for import_dec in &x.nodes.0.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.0.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.0.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        scope\n                            .defs\n                            .push(Box::new(port_dec_ansi(tree, ansi_dec, event_iter, url)?))\n                    }\n                }\n            }\n        }\n        ProgramDeclaration::Wildcard(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.1));\n            scope.end = get_loc(tree, RefNode::Keyword(&x.nodes.7));\n            let ident = get_ident(tree, RefNode::ProgramIdentifier(&x.nodes.2));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ProgramIdentifier);\n        }\n        ProgramDeclaration::ExternNonansi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::ProgramIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ProgramIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n        }\n        ProgramDeclaration::ExternAnsi(x) => {\n            scope.start = get_loc(tree, RefNode::Keyword(&x.nodes.0));\n            scope.end = get_loc(tree, RefNode::Symbol(&x.nodes.1.nodes.7));\n            let ident = get_ident(tree, RefNode::ProgramIdentifier(&x.nodes.1.nodes.3));\n            scope.ident = ident.0;\n            scope.byte_idx = ident.1;\n            let type_str = &mut scope.type_str;\n            advance_until_leave!(type_str, tree, event_iter, RefNode::ProgramIdentifier);\n            for import_dec in &x.nodes.1.nodes.4 {\n                let imports = package_import(tree, import_dec, event_iter, url)?;\n                for import in imports {\n                    scope.defs.push(Box::new(import));\n                }\n            }\n            if let Some(pport_list) = &x.nodes.1.nodes.5 {\n                let pports = param_port_list(tree, pport_list, event_iter, url)?;\n                for pport in pports {\n                    scope.defs.push(Box::new(pport));\n                }\n            }\n            if let Some(list_port_decs) = &x.nodes.1.nodes.6 {\n                if let Some(port_decs) = &list_port_decs.nodes.0.nodes.1 {\n                    for _ in port_decs.contents() {\n                        let ansi_dec = skip_until_enter!(\n                            tree,\n                            event_iter,\n                            RefNode::AnsiPortDeclaration,\n                            &AnsiPortDeclaration\n                        )?;\n                        scope\n                            .defs\n                            .push(Box::new(port_dec_ansi(tree, ansi_dec, event_iter, url)?))\n                    }\n                }\n            }\n        }\n    }\n\n    let (scopes, mut defs) =\n        match_until_leave!(tree, event_iter, url, RefNode::ProgramDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::MODULE;\n    scope.symbol_kind = SymbolKind::MODULE;\n    Some(scope)\n}\n\npub fn package_dec(\n    tree: &SyntaxTree,\n    node: &PackageDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    scope.start = get_loc(tree, RefNode::Keyword(&node.nodes.1));\n    scope.end = get_loc(tree, RefNode::Keyword(&node.nodes.7));\n    let ident = get_ident(tree, RefNode::PackageIdentifier(&node.nodes.3));\n    scope.ident = ident.0;\n    scope.byte_idx = ident.1;\n    let type_str = &mut scope.type_str;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::PackageIdentifier);\n\n    let (scopes, mut defs) =\n        match_until_leave!(tree, event_iter, url, RefNode::PackageDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::MODULE;\n    scope.symbol_kind = SymbolKind::PACKAGE;\n    Some(scope)\n}\n\npub fn config_dec(\n    tree: &SyntaxTree,\n    node: &ConfigDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericScope> {\n    let mut scope: GenericScope = GenericScope::new(url);\n    scope.start = get_loc(tree, RefNode::Keyword(&node.nodes.0));\n    scope.end = get_loc(tree, RefNode::Keyword(&node.nodes.6));\n    let ident = get_ident(tree, RefNode::ConfigIdentifier(&node.nodes.1));\n    scope.ident = ident.0;\n    scope.byte_idx = ident.1;\n    let type_str = &mut scope.type_str;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::ConfigIdentifier);\n    for localparam in &node.nodes.3 {\n        let params = localparam_dec(tree, &localparam.0, event_iter, url)?;\n        for param in params {\n            scope.defs.push(Box::new(param));\n        }\n    }\n\n    let (scopes, mut defs) = match_until_leave!(tree, event_iter, url, RefNode::ConfigDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    scope.completion_kind = CompletionItemKind::MODULE;\n    scope.symbol_kind = SymbolKind::MODULE;\n    Some(scope)\n}\n\npub fn class_dec(\n    tree: &SyntaxTree,\n    node: &ClassDeclaration,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<ClassDec> {\n    let mut scope: ClassDec = ClassDec::new(url);\n    scope.start = get_loc(tree, RefNode::Keyword(&node.nodes.1));\n    scope.end = get_loc(tree, RefNode::Keyword(&node.nodes.9));\n    let ident = get_ident(tree, RefNode::ClassIdentifier(&node.nodes.3));\n    scope.ident = ident.0;\n    scope.byte_idx = ident.1;\n    let type_str = &mut scope.type_str;\n    advance_until_leave!(type_str, tree, event_iter, RefNode::ClassIdentifier);\n    if let Some(pport_list) = &node.nodes.4 {\n        let pports = param_port_list(tree, pport_list, event_iter, url)?;\n        for pport in pports {\n            scope.defs.push(Box::new(pport));\n        }\n    }\n    if let Some(extend) = &node.nodes.5 {\n        if let Some(package_scope) = &extend.1.nodes.0.nodes.0 {\n            match package_scope {\n                PackageScope::Package(x) => {\n                    let ident = get_ident(tree, RefNode::PackageIdentifier(&x.nodes.0));\n                    scope.extends.1 = Some(ident.0);\n                }\n                PackageScope::Unit(_) => {}\n            }\n        }\n        let ident = get_ident(tree, RefNode::ClassIdentifier(&extend.1.nodes.0.nodes.1));\n        scope.extends.0.push(ident.0);\n        for class in &extend.1.nodes.2 {\n            let ident = get_ident(tree, RefNode::ClassIdentifier(&class.1));\n            scope.extends.0.push(ident.0);\n        }\n    }\n    if let Some(interfaces) = &node.nodes.6 {\n        for idec in interfaces.1.contents() {\n            let ident = get_ident(tree, RefNode::ClassIdentifier(&idec.nodes.0.nodes.1));\n            let mut interface: (String, Option<String>) = (ident.0, None);\n            if let Some(package_scope) = &idec.nodes.0.nodes.0 {\n                match package_scope {\n                    PackageScope::Package(x) => {\n                        let ident = get_ident(tree, RefNode::PackageIdentifier(&x.nodes.0));\n                        interface.1 = Some(ident.0);\n                    }\n                    PackageScope::Unit(_) => {}\n                }\n            }\n            scope.implements.push(interface);\n        }\n    }\n\n    let (scopes, mut defs) = match_until_leave!(tree, event_iter, url, RefNode::ClassDeclaration)?;\n    scope.scopes = scopes;\n    scope.defs.append(&mut defs);\n    Some(scope)\n}\n\n// `define definition\npub fn text_macro_def(\n    tree: &SyntaxTree,\n    node: &TextMacroDefinition,\n    event_iter: &mut EventIter,\n    url: &Url,\n) -> Option<GenericDec> {\n    let mut text_macro = GenericDec::new(url);\n    let ident = get_ident(tree, RefNode::TextMacroIdentifier(&node.nodes.2.nodes.0));\n    text_macro.ident = ident.0;\n    text_macro.byte_idx = ident.1;\n    let type_str = &mut text_macro.type_str;\n    advance_until_enter!(\n        type_str,\n        tree,\n        event_iter,\n        RefNode::TextMacroIdentifier,\n        &TextMacroIdentifier\n    );\n    text_macro.completion_kind = CompletionItemKind::FUNCTION;\n    text_macro.symbol_kind = SymbolKind::FUNCTION;\n    Some(text_macro)\n}\n"
  },
  {
    "path": "src/definition.rs",
    "content": "use crate::definition::extract_defs::get_ident;\nuse crate::server::LSPServer;\nuse crate::sources::LSPSupport;\nuse log::{debug, trace};\nuse ropey::{Rope, RopeSlice};\nuse sv_parser::*;\nuse tower_lsp::lsp_types::*;\n\npub mod def_types;\npub use def_types::*;\n\nmod extract_defs;\nuse extract_defs::*;\n\nimpl LSPServer {\n    pub fn goto_definition(&self, params: GotoDefinitionParams) -> Option<GotoDefinitionResponse> {\n        let doc = params.text_document_position_params.text_document.uri;\n        let pos = params.text_document_position_params.position;\n        let file_id = self.srcs.get_id(&doc).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n        let token = get_definition_token(file.text.line(pos.line as usize), pos);\n        debug!(\"goto definition, token: {}\", &token);\n        let scope_tree = self.srcs.scope_tree.read().ok()?;\n        trace!(\"{:#?}\", scope_tree.as_ref()?);\n        let def = scope_tree\n            .as_ref()?\n            .get_definition(&token, file.text.pos_to_byte(&pos), &doc)?;\n        let def_pos = file.text.byte_to_pos(def.byte_idx());\n        debug!(\"def: {:?}\", def_pos);\n        Some(GotoDefinitionResponse::Scalar(Location::new(\n            def.url(),\n            Range::new(def_pos, def_pos),\n        )))\n    }\n\n    pub fn hover(&self, params: HoverParams) -> Option<Hover> {\n        let doc = params.text_document_position_params.text_document.uri;\n        let pos = params.text_document_position_params.position;\n        let file_id = self.srcs.get_id(&doc).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n        let token = get_definition_token(file.text.line(pos.line as usize), pos);\n        debug!(\"hover, token: {}\", &token);\n        let scope_tree = self.srcs.scope_tree.read().ok()?;\n        let def = scope_tree\n            .as_ref()?\n            .get_definition(&token, file.text.pos_to_byte(&pos), &doc)?;\n        let def_line = file.text.byte_to_line(def.byte_idx());\n        Some(Hover {\n            contents: HoverContents::Scalar(MarkedString::LanguageString(LanguageString {\n                language: \"systemverilog\".to_owned(),\n                value: get_hover(&file.text, def_line),\n            })),\n            range: None,\n        })\n    }\n\n    pub fn document_symbol(&self, params: DocumentSymbolParams) -> Option<DocumentSymbolResponse> {\n        let uri = params.text_document.uri;\n        let file_id = self.srcs.get_id(&uri).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n        let scope_tree = self.srcs.scope_tree.read().ok()?;\n        Some(DocumentSymbolResponse::Nested(\n            scope_tree.as_ref()?.document_symbols(&uri, &file.text),\n        ))\n    }\n\n    pub fn document_highlight(\n        &self,\n        params: DocumentHighlightParams,\n    ) -> Option<Vec<DocumentHighlight>> {\n        let uri = params.text_document_position_params.text_document.uri;\n        let pos = params.text_document_position_params.position;\n        let file_id = self.srcs.get_id(&uri).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n        let token = get_definition_token(file.text.line(pos.line as usize), pos);\n        let scope_tree = self.srcs.scope_tree.read().ok()?;\n        // use the byte_idx of the definition if possible, otherwise use the cursor\n        let byte_idx =\n            match scope_tree\n                .as_ref()?\n                .get_definition(&token, file.text.pos_to_byte(&pos), &uri)\n            {\n                Some(def) => def.byte_idx,\n                None => file.text.pos_to_byte(&pos),\n            };\n        let syntax_tree = file.syntax_tree.as_ref()?;\n        let references = all_identifiers(syntax_tree, &token);\n        Some(\n            scope_tree\n                .as_ref()?\n                .document_highlights(&uri, &file.text, references, byte_idx),\n        )\n    }\n}\n\n/// return all identifiers in a syntax tree matching a given token\nfn all_identifiers(syntax_tree: &SyntaxTree, token: &str) -> Vec<(String, usize)> {\n    let mut idents: Vec<(String, usize)> = Vec::new();\n    for node in syntax_tree {\n        if let RefNode::Identifier(_) = node {\n            let (ident, byte_idx) = get_ident(syntax_tree, node);\n            if ident == token {\n                idents.push((ident, byte_idx));\n            }\n        }\n    }\n    idents\n}\n\n/// retrieve the token the user invoked goto definition or hover on\nfn get_definition_token(line: RopeSlice, pos: Position) -> String {\n    let mut token = String::new();\n    let mut line_iter = line.chars();\n    for _ in 0..(line.utf16_cu_to_char(pos.character as usize)) {\n        line_iter.next();\n    }\n    let mut c = line_iter.prev();\n    while c.is_some() && (c.unwrap().is_alphanumeric() || c.unwrap() == '_') {\n        token.push(c.unwrap());\n        c = line_iter.prev();\n    }\n    token = token.chars().rev().collect();\n    line_iter = line.chars();\n    for _ in 0..(line.utf16_cu_to_char(pos.character as usize)) {\n        line_iter.next();\n    }\n    let mut c = line_iter.next();\n    while c.is_some() && (c.unwrap().is_alphanumeric() || c.unwrap() == '_') {\n        token.push(c.unwrap());\n        c = line_iter.next();\n    }\n    token\n}\n\ntype ScopesAndDefs = Option<(Vec<Box<dyn Scope>>, Vec<Box<dyn Definition>>)>;\n\n/// Take a given syntax node from a sv-parser syntax tree and extract out the definition/scope at\n/// that point.\npub fn match_definitions(\n    syntax_tree: &SyntaxTree,\n    event_iter: &mut EventIter,\n    node: RefNode,\n    url: &Url,\n) -> ScopesAndDefs {\n    let mut definitions: Vec<Box<dyn Definition>> = Vec::new();\n    let mut scopes: Vec<Box<dyn Scope>> = Vec::new();\n    match node {\n        RefNode::ModuleDeclaration(n) => {\n            let module = module_dec(syntax_tree, n, event_iter, url);\n            if module.is_some() {\n                scopes.push(Box::new(module?));\n            }\n        }\n        RefNode::InterfaceDeclaration(n) => {\n            let interface = interface_dec(syntax_tree, n, event_iter, url);\n            if interface.is_some() {\n                scopes.push(Box::new(interface?));\n            }\n        }\n        RefNode::UdpDeclaration(n) => {\n            let dec = udp_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::ProgramDeclaration(n) => {\n            let dec = program_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::PackageDeclaration(n) => {\n            let dec = package_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::ConfigDeclaration(n) => {\n            let dec = config_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::ClassDeclaration(n) => {\n            let dec = class_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::PortDeclaration(n) => {\n            let ports = port_dec_non_ansi(syntax_tree, n, event_iter, url);\n            if ports.is_some() {\n                for port in ports? {\n                    definitions.push(Box::new(port));\n                }\n            }\n        }\n        RefNode::NetDeclaration(n) => {\n            let nets = net_dec(syntax_tree, n, event_iter, url);\n            if nets.is_some() {\n                for net in nets? {\n                    definitions.push(Box::new(net));\n                }\n            }\n        }\n        RefNode::DataDeclaration(n) => {\n            let vars = data_dec(syntax_tree, n, event_iter, url);\n            if let Some(vars) = vars {\n                for var in vars {\n                    match var {\n                        Declaration::Dec(dec) => definitions.push(Box::new(dec)),\n                        Declaration::Import(dec) => definitions.push(Box::new(dec)),\n                        Declaration::Scope(scope) => scopes.push(Box::new(scope)),\n                    }\n                }\n            }\n        }\n        RefNode::ParameterDeclaration(n) => {\n            let vars = param_dec(syntax_tree, n, event_iter, url);\n            if vars.is_some() {\n                for var in vars? {\n                    definitions.push(Box::new(var));\n                }\n            }\n        }\n        RefNode::LocalParameterDeclaration(n) => {\n            let vars = localparam_dec(syntax_tree, n, event_iter, url);\n            if vars.is_some() {\n                for var in vars? {\n                    definitions.push(Box::new(var));\n                }\n            }\n        }\n        RefNode::FunctionDeclaration(n) => {\n            let dec = function_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::TaskDeclaration(n) => {\n            let dec = task_dec(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                scopes.push(Box::new(dec?));\n            }\n        }\n        RefNode::ModportDeclaration(n) => {\n            let decs = modport_dec(syntax_tree, n, event_iter, url);\n            if decs.is_some() {\n                for dec in decs? {\n                    definitions.push(Box::new(dec));\n                }\n            }\n        }\n        RefNode::ModuleInstantiation(n) => {\n            let decs = module_inst(syntax_tree, n, event_iter, url);\n            if decs.is_some() {\n                for dec in decs? {\n                    definitions.push(Box::new(dec));\n                }\n            }\n        }\n        RefNode::TextMacroDefinition(n) => {\n            let dec = text_macro_def(syntax_tree, n, event_iter, url);\n            if dec.is_some() {\n                definitions.push(Box::new(dec?));\n            }\n        }\n        _ => (),\n    }\n    Some((scopes, definitions))\n}\n\n/// convert the syntax tree to a scope tree\n/// the root node is the global scope\npub fn get_scopes(syntax_tree: &SyntaxTree, url: &Url) -> Option<GenericScope> {\n    trace!(\"{}\", syntax_tree);\n    let mut scopes: Vec<Box<dyn Scope>> = Vec::new();\n    let mut global_scope: GenericScope = GenericScope::new(url);\n    global_scope.ident = \"global\".to_string();\n    let mut event_iter = syntax_tree.into_iter().event();\n    // iterate over each enter event and extract out any scopes or definitions\n    // match_definitions is recursively called so we get a tree in the end\n    while let Some(event) = event_iter.next() {\n        match event {\n            NodeEvent::Enter(node) => {\n                let mut result = match_definitions(syntax_tree, &mut event_iter, node, url)?;\n                global_scope.defs.append(&mut result.1);\n                scopes.append(&mut result.0);\n            }\n            NodeEvent::Leave(_) => (),\n        }\n    }\n    global_scope.scopes.append(&mut scopes);\n    Some(global_scope)\n}\n\n/// get the hover information\nfn get_hover(doc: &Rope, line: usize) -> String {\n    if line == 0 {\n        return doc.line(line).to_string();\n    }\n    let mut hover: Vec<String> = Vec::new();\n    let mut multiline: bool = false;\n    let mut valid: bool = true;\n    let mut current: String = doc.line(line).to_string();\n    let ltrim: String = \" \".repeat(current.len() - current.trim_start().len());\n    let mut line_idx = line;\n\n    // iterate upwards from the definition, and grab the comments\n    while valid {\n        hover.push(current.clone());\n        line_idx -= 1;\n        valid = false;\n        if line_idx > 0 {\n            current = doc.line(line_idx).to_string();\n            let currentl = current.clone().trim_start().to_owned();\n            let currentr = current.clone().trim_end().to_owned();\n            if currentl.starts_with(\"/*\") && currentr.ends_with(\"*/\") {\n                valid = true;\n            } else if currentr.ends_with(\"*/\") {\n                multiline = true;\n                valid = true;\n            } else if currentl.starts_with(\"/*\") {\n                multiline = false;\n                valid = true;\n            } else {\n                valid = currentl.starts_with(\"//\") || multiline;\n            }\n        }\n    }\n    hover.reverse();\n    let mut result: Vec<String> = Vec::new();\n    for i in hover {\n        if let Some(stripped) = i.strip_prefix(&ltrim) {\n            result.push(stripped.to_owned());\n        } else {\n            result.push(i);\n        }\n    }\n    result.join(\"\").trim_end().to_owned()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::sources::{parse, LSPSupport};\n    use crate::support::test_init;\n    use ropey::Rope;\n    use std::fs::read_to_string;\n    use std::path::PathBuf;\n\n    #[test]\n    fn test_definition_token() {\n        test_init();\n        let line = Rope::from_str(\"assign ab_c[2:0] = 3'b000;\");\n        let token = get_definition_token(line.line(0), Position::new(0, 10));\n        assert_eq!(token, \"ab_c\".to_owned());\n    }\n\n    #[test]\n    fn test_get_definition() {\n        test_init();\n        let mut d = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n        d.push(\"test_data/definition_test.sv\");\n        let text = read_to_string(d).unwrap();\n        let doc = Rope::from_str(&text);\n        let url = Url::parse(\"file:///test_data/definition_test.sv\").unwrap();\n        let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();\n        trace!(\"{}\", &syntax_tree);\n        let scope_tree = get_scopes(&syntax_tree, &url).unwrap();\n        trace!(\"{:#?}\", &scope_tree);\n        for def in &scope_tree.defs {\n            trace!(\"{:?} {:?}\", def, doc.byte_to_pos(def.byte_idx()));\n        }\n        let token = get_definition_token(doc.line(3), Position::new(3, 13));\n        for def in scope_tree.defs {\n            if token == def.ident() {\n                assert_eq!(doc.byte_to_pos(def.byte_idx()), Position::new(3, 9))\n            }\n        }\n    }\n\n    #[test]\n    fn test_hover() {\n        test_init();\n        let text = r#\"\n// module test\n// test module\nmodule test;\n  /* a */\n  logic a;\n  /**\n    * b\n  */\n  logic b;\n  endmodule\"#;\n        let doc = Rope::from_str(text);\n        eprintln!(\"{}\", get_hover(&doc, 2));\n        assert_eq!(\n            get_hover(&doc, 3),\n            r#\"// module test\n// test module\nmodule test;\"#\n                .to_owned()\n        );\n        assert_eq!(\n            get_hover(&doc, 9),\n            r#\"/**\n  * b\n*/\nlogic b;\"#\n                .to_owned()\n        );\n    }\n\n    #[test]\n    fn test_symbols() {\n        test_init();\n        let text = r#\"\nmodule test;\n  logic a;\n  logic b;\nendmodule\"#;\n        let doc = Rope::from_str(text);\n        let url = Url::parse(\"file:///test.sv\").unwrap();\n        let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();\n        let scope_tree = get_scopes(&syntax_tree, &url).unwrap();\n        let symbol = scope_tree.document_symbols(&url, &doc);\n        let symbol = symbol.first().unwrap();\n        assert_eq!(&symbol.name, \"test\");\n        let names: Vec<String> = symbol\n            .children\n            .as_ref()\n            .unwrap()\n            .iter()\n            .map(|x| x.name.clone())\n            .collect();\n        assert!(names.contains(&\"a\".to_string()));\n        assert!(names.contains(&\"b\".to_string()));\n    }\n\n    #[test]\n    fn test_highlight() {\n        test_init();\n        let text = r#\"\nmodule test;\n  logic clk;\n  assign clk = 1'b1;\nendmodule\"#;\n        let doc = Rope::from_str(text);\n        let url = Url::parse(\"file:///test.sv\").unwrap();\n        let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();\n        let scope_tree = get_scopes(&syntax_tree, &url).unwrap();\n        let references = all_identifiers(&syntax_tree, \"clk\");\n        let highlights = scope_tree.document_highlights(\n            &url,\n            &doc,\n            references,\n            doc.pos_to_byte(&Position::new(2, 8)),\n        );\n        let expected = vec![\n            DocumentHighlight {\n                range: Range {\n                    start: Position {\n                        line: 2,\n                        character: 8,\n                    },\n                    end: Position {\n                        line: 2,\n                        character: 11,\n                    },\n                },\n                kind: None,\n            },\n            DocumentHighlight {\n                range: Range {\n                    start: Position {\n                        line: 3,\n                        character: 9,\n                    },\n                    end: Position {\n                        line: 3,\n                        character: 12,\n                    },\n                },\n                kind: None,\n            },\n        ];\n        assert_eq!(highlights, expected)\n    }\n}\n"
  },
  {
    "path": "src/diagnostics.rs",
    "content": "use crate::server::ProjectConfig;\n#[cfg(feature = \"slang\")]\nuse path_clean::PathClean;\nuse regex::Regex;\nuse ropey::Rope;\n#[cfg(feature = \"slang\")]\nuse std::env::current_dir;\n#[cfg(feature = \"slang\")]\nuse std::path::Path;\nuse std::path::PathBuf;\nuse std::process::{Command, Stdio};\nuse tower_lsp::lsp_types::*;\n#[cfg(feature = \"slang\")]\nuse veridian_slang::slang_compile;\nuse walkdir::DirEntry;\n#[cfg(feature = \"slang\")]\nuse walkdir::WalkDir;\n\n#[cfg(feature = \"slang\")]\npub fn get_diagnostics(\n    uri: Url,\n    rope: &Rope,\n    files: Vec<Url>,\n    conf: &ProjectConfig,\n) -> PublishDiagnosticsParams {\n    if !(cfg!(test) && (uri.to_string().starts_with(\"file:///test\"))) {\n        let paths = get_paths(files, conf.auto_search_workdir);\n        let mut diagnostics = {\n            if conf.verilator.syntax.enabled {\n                if let Ok(path) = uri.to_file_path() {\n                    verilator_syntax(\n                        rope,\n                        path,\n                        &conf.verilator.syntax.path,\n                        &conf.verilator.syntax.args,\n                    )\n                    .unwrap_or_default()\n                } else {\n                    Vec::new()\n                }\n            } else if conf.verible.syntax.enabled {\n                verible_syntax(rope, &conf.verible.syntax.path, &conf.verible.syntax.args)\n                    .unwrap_or_default()\n            } else {\n                Vec::new()\n            }\n        };\n        diagnostics.append(&mut parse_report(\n            uri.clone(),\n            slang_compile(paths).unwrap(),\n        ));\n        PublishDiagnosticsParams {\n            uri,\n            diagnostics,\n            version: None,\n        }\n    } else {\n        PublishDiagnosticsParams {\n            uri,\n            diagnostics: Vec::new(),\n            version: None,\n        }\n    }\n}\n\n#[cfg(not(feature = \"slang\"))]\npub fn get_diagnostics(\n    uri: Url,\n    rope: &Rope,\n    #[allow(unused_variables)] files: Vec<Url>,\n    conf: &ProjectConfig,\n) -> PublishDiagnosticsParams {\n    if !(cfg!(test) && (uri.to_string().starts_with(\"file:///test\"))) {\n        let diagnostics = {\n            if conf.verilator.syntax.enabled {\n                if let Ok(path) = uri.to_file_path() {\n                    verilator_syntax(\n                        rope,\n                        path,\n                        &conf.verilator.syntax.path,\n                        &conf.verilator.syntax.args,\n                    )\n                    .unwrap_or_default()\n                } else {\n                    Vec::new()\n                }\n            } else if conf.verible.syntax.enabled {\n                verible_syntax(rope, &conf.verible.syntax.path, &conf.verible.syntax.args)\n                    .unwrap_or_default()\n            } else {\n                Vec::new()\n            }\n        };\n        PublishDiagnosticsParams {\n            uri,\n            diagnostics,\n            version: None,\n        }\n    } else {\n        PublishDiagnosticsParams {\n            uri,\n            diagnostics: Vec::new(),\n            version: None,\n        }\n    }\n}\n\n/// recursively find source file paths from working directory\n/// and open files\n#[cfg(feature = \"slang\")]\nfn get_paths(files: Vec<Url>, search_workdir: bool) -> Vec<PathBuf> {\n    // check recursively from working dir for source files\n    let mut paths: Vec<PathBuf> = Vec::new();\n    if search_workdir {\n        let walker = WalkDir::new(\".\").into_iter();\n        for entry in walker.filter_entry(|e| !is_hidden(e)) {\n            let entry = entry.unwrap();\n            if entry.file_type().is_file() {\n                let extension = entry.path().extension().unwrap();\n\n                if extension == \"sv\" || extension == \"svh\" || extension == \"v\" || extension == \"vh\"\n                {\n                    paths.push(entry.path().to_path_buf());\n                }\n            }\n        }\n    }\n\n    // check recursively from opened files for source files\n    for file in files {\n        if let Ok(path) = file.to_file_path() {\n            if !paths.contains(&path) {\n                let walker = WalkDir::new(path.parent().unwrap()).into_iter();\n                for entry in walker.filter_entry(|e| !is_hidden(e)).flatten() {\n                    if entry.file_type().is_file() && entry.path().extension().is_some() {\n                        let extension = entry.path().extension().unwrap();\n\n                        if extension == \"sv\"\n                            || extension == \"svh\"\n                            || extension == \"v\"\n                            || extension == \"vh\"\n                        {\n                            let entry_path = entry.path().to_path_buf();\n                            if !paths.contains(&entry_path) {\n                                paths.push(entry_path);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n    paths\n}\n\npub fn is_hidden(entry: &DirEntry) -> bool {\n    entry\n        .file_name()\n        .to_str()\n        .map(|s| s.starts_with('.'))\n        .unwrap_or(false)\n}\n\n#[cfg(feature = \"slang\")]\n/// parse a report from slang\nfn parse_report(uri: Url, report: String) -> Vec<Diagnostic> {\n    let mut diagnostics: Vec<Diagnostic> = Vec::new();\n    for line in report.lines() {\n        let diag: Vec<&str> = line.splitn(5, ':').collect();\n        if absolute_path(diag.first().unwrap()) == uri.to_file_path().unwrap().as_os_str() {\n            let pos = Position::new(\n                diag.get(1).unwrap().parse::<u32>().unwrap() - 1,\n                diag.get(2).unwrap().parse::<u32>().unwrap() - 1,\n            );\n            diagnostics.push(Diagnostic::new(\n                Range::new(pos, pos),\n                slang_severity(diag.get(3).unwrap()),\n                None,\n                Some(\"slang\".to_owned()),\n                (*diag.get(4).unwrap()).to_owned(),\n                None,\n                None,\n            ))\n        }\n    }\n    diagnostics\n}\n\n#[cfg(feature = \"slang\")]\nfn slang_severity(severity: &str) -> Option<DiagnosticSeverity> {\n    match severity {\n        \" error\" => Some(DiagnosticSeverity::ERROR),\n        \" warning\" => Some(DiagnosticSeverity::WARNING),\n        \" note\" => Some(DiagnosticSeverity::INFORMATION),\n        _ => None,\n    }\n}\n\n#[cfg(feature = \"slang\")]\n// convert relative path to absolute\nfn absolute_path(path_str: &str) -> PathBuf {\n    let path = Path::new(path_str);\n    current_dir().unwrap().join(path).clean()\n}\n\n/// convert captured severity string to DiagnosticSeverity\nfn verilator_severity(severity: &str) -> Option<DiagnosticSeverity> {\n    match severity {\n        \"Error\" => Some(DiagnosticSeverity::ERROR),\n        s if s.starts_with(\"Warning\") => Some(DiagnosticSeverity::WARNING),\n        // NOTE: afaik, verilator doesn't have an info or hint severity\n        _ => Some(DiagnosticSeverity::INFORMATION),\n    }\n}\n\n/// syntax checking using verilator --lint-only\nfn verilator_syntax(\n    rope: &Rope,\n    file_path: PathBuf,\n    verilator_syntax_path: &str,\n    verilator_syntax_args: &[String],\n) -> Option<Vec<Diagnostic>> {\n    let mut child = Command::new(verilator_syntax_path)\n        .stdin(Stdio::piped())\n        .stderr(Stdio::piped())\n        .stdout(Stdio::piped())\n        .args(verilator_syntax_args)\n        .arg(file_path.to_str()?)\n        .spawn()\n        .ok()?;\n\n    static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();\n    let re = RE.get_or_init(|| {\n        Regex::new(\n            r\"%(?P<severity>Error|Warning)(-(?P<warning_type>[A-Z0-9_]+))?: (?P<filepath>[^:]+):(?P<line>\\d+):((?P<col>\\d+):)? ?(?P<message>.*)\",\n        )\n        .unwrap()\n    });\n    // write file to stdin, read output from stdout\n    rope.write_to(child.stdin.as_mut()?).ok()?;\n    let output = child.wait_with_output().ok()?;\n    if !output.status.success() {\n        let mut diags: Vec<Diagnostic> = Vec::new();\n        let raw_output = String::from_utf8(output.stderr).ok()?;\n        let filtered_output = raw_output\n            .lines()\n            .filter(|line| line.starts_with('%'))\n            .collect::<Vec<&str>>();\n        for error in filtered_output {\n            let caps = match re.captures(error) {\n                Some(caps) => caps,\n                None => continue,\n            };\n\n            // check if diagnostic is for this file, since verilator can provide diagnostics for\n            // included files\n            if caps.name(\"filepath\")?.as_str() != file_path.to_str().unwrap_or(\"\") {\n                continue;\n            }\n            let severity = verilator_severity(caps.name(\"severity\")?.as_str());\n            let line: u32 = caps.name(\"line\")?.as_str().to_string().parse().ok()?;\n            let col: u32 = caps.name(\"col\").map_or(\"1\", |m| m.as_str()).parse().ok()?;\n            let pos = Position::new(line - 1, col - 1);\n            let msg = match severity {\n                Some(DiagnosticSeverity::ERROR) => caps.name(\"message\")?.as_str().to_string(),\n                Some(DiagnosticSeverity::WARNING) => format!(\n                    \"{}: {}\",\n                    caps.name(\"warning_type\")?.as_str(),\n                    caps.name(\"message\")?.as_str()\n                ),\n                _ => \"\".to_string(),\n            };\n            diags.push(Diagnostic::new(\n                Range::new(pos, pos),\n                severity,\n                None,\n                Some(\"verilator\".to_string()),\n                msg,\n                None,\n                None,\n            ));\n        }\n        Some(diags)\n    } else {\n        None\n    }\n}\n\n/// syntax checking using verible-verilog-syntax\nfn verible_syntax(\n    rope: &Rope,\n    verible_syntax_path: &str,\n    verible_syntax_args: &[String],\n) -> Option<Vec<Diagnostic>> {\n    let mut child = Command::new(verible_syntax_path)\n        .stdin(Stdio::piped())\n        .stderr(Stdio::piped())\n        .stdout(Stdio::piped())\n        .args(verible_syntax_args)\n        .arg(\"-\")\n        .spawn()\n        .ok()?;\n\n    static RE: std::sync::OnceLock<Regex> = std::sync::OnceLock::new();\n    let re = RE.get_or_init(|| {\n        Regex::new(\n            r\"^.+:(?P<line>\\d*):(?P<startcol>\\d*)(?:-(?P<endcol>\\d*))?:\\s(?P<message>.*)\\s.*$\",\n        )\n        .unwrap()\n    });\n    // write file to stdin, read output from stdout\n    rope.write_to(child.stdin.as_mut()?).ok()?;\n    let output = child.wait_with_output().ok()?;\n    if !output.status.success() {\n        let mut diags: Vec<Diagnostic> = Vec::new();\n        let raw_output = String::from_utf8(output.stdout).ok()?;\n        for error in raw_output.lines() {\n            let caps = re.captures(error)?;\n            let line: u32 = caps.name(\"line\")?.as_str().parse().ok()?;\n            let startcol: u32 = caps.name(\"startcol\")?.as_str().parse().ok()?;\n            let endcol: Option<u32> = match caps.name(\"endcol\").map(|e| e.as_str().parse()) {\n                Some(Ok(e)) => Some(e),\n                None => None,\n                Some(Err(_)) => return None,\n            };\n            let start_pos = Position::new(line - 1, startcol - 1);\n            let end_pos = Position::new(line - 1, endcol.unwrap_or(startcol) - 1);\n            diags.push(Diagnostic::new(\n                Range::new(start_pos, end_pos),\n                Some(DiagnosticSeverity::ERROR),\n                None,\n                Some(\"verible\".to_string()),\n                caps.name(\"message\")?.as_str().to_string(),\n                None,\n                None,\n            ));\n        }\n        Some(diags)\n    } else {\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::support::test_init;\n    use std::fs::File;\n    use std::io::Write;\n    use tempdir::TempDir;\n\n    #[test]\n    #[cfg(feature = \"slang\")]\n    fn test_diagnostics() {\n        test_init();\n        let uri = Url::from_file_path(absolute_path(\"test_data/diag/diag_test.sv\")).unwrap();\n        let expected = PublishDiagnosticsParams::new(\n            uri.clone(),\n            vec![Diagnostic::new(\n                Range::new(Position::new(3, 13), Position::new(3, 13)),\n                Some(DiagnosticSeverity::WARNING),\n                None,\n                Some(\"slang\".to_owned()),\n                \" cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\".to_owned(),\n                None,\n                None,\n            )],\n            None,\n        );\n        let diag = get_diagnostics(\n            uri.clone(),\n            &Rope::default(),\n            vec![uri],\n            &ProjectConfig::default(),\n        );\n        assert_eq!(diag.uri, expected.uri);\n        assert_eq!(diag.version, expected.version);\n        assert_eq!(diag.diagnostics.last(), expected.diagnostics.last());\n    }\n\n    #[test]\n    fn test_unsaved_file() {\n        test_init();\n        let uri = Url::parse(\"file://test.sv\").unwrap();\n        get_diagnostics(\n            uri.clone(),\n            &Rope::default(),\n            vec![uri],\n            &ProjectConfig::default(),\n        );\n    }\n\n    #[test]\n    fn test_verible_syntax() {\n        let text = r#\"module test;\n    logic abc;\n    logic abcd;\n\n  a\nendmodule\n\"#;\n        let doc = Rope::from_str(text);\n        let errors = verible_syntax(&doc, \"verible-verilog-syntax\", &[])\n            .expect(\"verible-verilog-syntax not found, test can not run\");\n        let expected: Vec<Diagnostic> = vec![Diagnostic {\n            range: Range {\n                start: Position {\n                    line: 5,\n                    character: 0,\n                },\n                end: Position {\n                    line: 5,\n                    character: 8,\n                },\n            },\n            severity: Some(DiagnosticSeverity::ERROR),\n            code: None,\n            source: Some(\"verible\".to_string()),\n            message: \"syntax error at token\".to_string(),\n            related_information: None,\n            tags: None,\n            code_description: None,\n            data: None,\n        }];\n        assert_eq!(errors, expected);\n    }\n\n    #[test]\n    fn test_verilator_syntax() {\n        let text = r#\"module test;\n    logic abc;\n    logic abcd;\n\n  a\nendmodule\n\"#;\n        let doc = Rope::from_str(text);\n\n        // verilator can't read from stdin so we must create a temp dir to place our\n        // test file\n        let dir = TempDir::new(\"verilator_test\").unwrap();\n        let file_path_1 = dir.path().join(\"test.sv\");\n        let mut f = File::create(&file_path_1).unwrap();\n        f.write_all(text.as_bytes()).unwrap();\n        f.sync_all().unwrap();\n\n        let errors = verilator_syntax(\n            &doc,\n            file_path_1,\n            \"verilator\",\n            &[\n                \"--lint-only\".to_string(),\n                \"--sv\".to_string(),\n                \"-Wall\".to_string(),\n            ],\n        )\n        .expect(\"verilator not found, test can not run\");\n\n        drop(f);\n        dir.close().unwrap();\n\n        let expected: Vec<Diagnostic> = vec![Diagnostic {\n            range: Range {\n                start: Position {\n                    line: 5,\n                    character: 0,\n                },\n                end: Position {\n                    line: 5,\n                    character: 0,\n                },\n            },\n            severity: Some(DiagnosticSeverity::ERROR),\n            code: None,\n            source: Some(\"verilator\".to_string()),\n            message: \"syntax error, unexpected endmodule, expecting IDENTIFIER or randomize\"\n                .to_string(),\n            related_information: None,\n            tags: None,\n            code_description: None,\n            data: None,\n        }];\n        assert_eq!(errors[0].severity, expected[0].severity);\n        assert_eq!(errors[0].range.start.line, expected[0].range.start.line);\n        assert_eq!(errors[0].range.end.line, expected[0].range.end.line);\n        assert!(errors[0].message.contains(\"syntax error\"));\n    }\n}\n"
  },
  {
    "path": "src/format.rs",
    "content": "use crate::server::LSPServer;\nuse crate::sources::LSPSupport;\nuse log::info;\nuse ropey::Rope;\nuse std::process::{Command, Stdio};\nuse tower_lsp::lsp_types::*;\n\nimpl LSPServer {\n    pub fn formatting(&self, params: DocumentFormattingParams) -> Option<Vec<TextEdit>> {\n        let uri = params.text_document.uri;\n        info!(\"formatting {}\", &uri);\n        let file_id = self.srcs.get_id(&uri).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n\n        let conf = self.conf.read().unwrap();\n        if conf.verible.format.enabled {\n            Some(vec![TextEdit::new(\n                Range::new(\n                    file.text.char_to_pos(0),\n                    file.text.char_to_pos(file.text.len_chars()),\n                ),\n                format_document(\n                    &file.text,\n                    None,\n                    &conf.verible.format.path,\n                    &conf.verible.format.args,\n                )?,\n            )])\n        } else {\n            None\n        }\n    }\n\n    pub fn range_formatting(&self, params: DocumentRangeFormattingParams) -> Option<Vec<TextEdit>> {\n        let uri = params.text_document.uri;\n        info!(\"range formatting {}\", &uri);\n        let file_id = self.srcs.get_id(&uri).to_owned();\n        self.srcs.wait_parse_ready(file_id, false);\n        let file = self.srcs.get_file(file_id)?;\n        let file = file.read().ok()?;\n\n        let conf = self.conf.read().unwrap();\n        if conf.verible.format.enabled {\n            Some(vec![TextEdit::new(\n                file.text.char_range_to_range(0..file.text.len_chars()),\n                format_document(\n                    &file.text,\n                    Some(params.range),\n                    &conf.verible.format.path,\n                    &conf.verible.format.args,\n                )?,\n            )])\n        } else {\n            None\n        }\n    }\n}\n\n/// format the document using verible-verilog-format\npub fn format_document(\n    rope: &Rope,\n    range: Option<Range>,\n    verible_format_path: &str,\n    verible_format_args: &[String],\n) -> Option<String> {\n    let mut child = Command::new(verible_format_path);\n    child\n        .stdin(Stdio::piped())\n        .stderr(Stdio::piped())\n        .stdout(Stdio::piped())\n        .args(verible_format_args);\n    // rangeFormatting\n    if let Some(r) = range {\n        child\n            .arg(\"--lines\")\n            .arg(format!(\"{}-{}\", r.start.line + 1, r.end.line + 1));\n    }\n    let mut child = child.arg(\"-\").spawn().ok()?;\n\n    // write file to stdin, read output from stdout\n    rope.write_to(child.stdin.as_mut()?).ok()?;\n    let output = child.wait_with_output().ok()?;\n    if output.status.success() {\n        info!(\"formatting succeeded\");\n        let raw_output = String::from_utf8(output.stdout).ok()?;\n        Some(raw_output)\n    } else {\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::server::ProjectConfig;\n    use crate::support::test_init;\n    use which::which;\n\n    #[test]\n    fn test_formatting() {\n        test_init();\n        let text = r#\"\nmodule test;\n  logic a;\n   logic b;\nendmodule\"#;\n        let text_fixed = r#\"\nmodule test;\n  logic a;\n  logic b;\nendmodule\n\"#;\n        let doc = Rope::from_str(text);\n        if which(\"verible-verilog-format\").is_ok() {\n            assert_eq!(\n                format_document(\n                    &doc,\n                    None,\n                    &ProjectConfig::default().verible.format.path,\n                    &[]\n                )\n                .unwrap(),\n                text_fixed.to_string()\n            );\n        }\n    }\n\n    #[test]\n    fn test_range_formatting() {\n        test_init();\n        let text = r#\"module t1;\n    logic a;\n logic b;\n         logic c;\nendmodule\n\n\nmodule t2;\n    logic a;\n logic b;\n         logic c;\nendmodule\"#;\n\n        let text_fixed = r#\"module t1;\n  logic a;\n  logic b;\n  logic c;\nendmodule\n\n\nmodule t2;\n    logic a;\n logic b;\n         logic c;\nendmodule\n\"#;\n        let doc = Rope::from_str(text);\n        if which(\"verible-verilog-format\").is_ok() {\n            assert_eq!(\n                format_document(\n                    &doc,\n                    Some(Range::new(Position::new(0, 0), Position::new(4, 9))),\n                    &ProjectConfig::default().verible.format.path,\n                    &[]\n                )\n                .unwrap(),\n                text_fixed.to_string()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![recursion_limit = \"256\"]\n\npub mod completion;\npub mod definition;\npub mod diagnostics;\npub mod format;\npub mod server;\npub mod sources;\npub mod support;\n"
  },
  {
    "path": "src/main.rs",
    "content": "#![recursion_limit = \"256\"]\n\nuse log::info;\nuse std::sync::Arc;\nuse structopt::StructOpt;\nuse tower_lsp::{LspService, Server};\n\nmod completion;\nmod definition;\nmod diagnostics;\nmod format;\nmod server;\nmod sources;\n#[cfg(test)]\nmod support;\nuse server::Backend;\n\n#[derive(StructOpt, Debug)]\n#[structopt(name = \"veridian\", about = \"A SystemVerilog/Verilog Language Server\")]\nstruct Opt {}\n\n#[tokio::main]\nasync fn main() {\n    let _ = Opt::from_args();\n    let log_handle = flexi_logger::Logger::with(flexi_logger::LogSpecification::info())\n        .start()\n        .unwrap();\n    info!(\"starting veridian...\");\n\n    let stdin = tokio::io::stdin();\n    let stdout = tokio::io::stdout();\n\n    let (service, messages) = LspService::new(|client| Arc::new(Backend::new(client, log_handle)));\n    Server::new(stdin, stdout, messages).serve(service).await;\n}\n"
  },
  {
    "path": "src/server.rs",
    "content": "use crate::sources::*;\n\nuse crate::completion::keyword::*;\nuse flexi_logger::LoggerHandle;\nuse log::{debug, info, warn};\nuse path_clean::PathClean;\nuse serde::{Deserialize, Serialize};\nuse std::env::current_dir;\nuse std::fs::File;\nuse std::io::Read;\nuse std::path::PathBuf;\nuse std::string::ToString;\nuse std::sync::{Mutex, RwLock};\nuse tower_lsp::jsonrpc::{Error, ErrorCode, Result};\nuse tower_lsp::lsp_types::*;\nuse tower_lsp::{Client, LanguageServer};\nuse which::which;\n\npub struct LSPServer {\n    pub srcs: Sources,\n    pub key_comps: Vec<CompletionItem>,\n    pub sys_tasks: Vec<CompletionItem>,\n    pub directives: Vec<CompletionItem>,\n    pub conf: RwLock<ProjectConfig>,\n    pub log_handle: Mutex<Option<LoggerHandle>>,\n}\n\nimpl LSPServer {\n    pub fn new(log_handle: Option<LoggerHandle>) -> LSPServer {\n        LSPServer {\n            srcs: Sources::new(),\n            key_comps: keyword_completions(KEYWORDS),\n            sys_tasks: other_completions(SYS_TASKS),\n            directives: other_completions(DIRECTIVES),\n            conf: RwLock::new(ProjectConfig::default()),\n            log_handle: Mutex::new(log_handle),\n        }\n    }\n}\n\npub struct Backend {\n    client: Client,\n    server: LSPServer,\n}\n\nimpl Backend {\n    pub fn new(client: Client, log_handle: LoggerHandle) -> Backend {\n        Backend {\n            client,\n            server: LSPServer::new(Some(log_handle)),\n        }\n    }\n}\n\n#[derive(strum_macros::Display, Debug, Serialize, Deserialize)]\npub enum LogLevel {\n    #[strum(serialize = \"error\")]\n    Error,\n    #[strum(serialize = \"warn\")]\n    Warn,\n    #[strum(serialize = \"info\")]\n    Info,\n    #[strum(serialize = \"debug\")]\n    Debug,\n    #[strum(serialize = \"trace\")]\n    Trace,\n}\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(default)]\npub struct ProjectConfig {\n    // if true, recursively search the working directory for files to run diagnostics on\n    pub auto_search_workdir: bool,\n    // list of directories with header files\n    pub include_dirs: Vec<String>,\n    // list of directories to recursively search for SystemVerilog/Verilog sources\n    pub source_dirs: Vec<String>,\n    // config options for verible tools\n    pub verible: Verible,\n    // config options for verilator tools\n    pub verilator: Verilator,\n    // log level\n    pub log_level: LogLevel,\n}\n\nimpl Default for ProjectConfig {\n    fn default() -> Self {\n        ProjectConfig {\n            auto_search_workdir: true,\n            include_dirs: Vec::new(),\n            source_dirs: Vec::new(),\n            verible: Verible::default(),\n            verilator: Verilator::default(),\n            log_level: LogLevel::Info,\n        }\n    }\n}\n\n#[derive(Default, Debug, Serialize, Deserialize)]\n#[serde(default)]\npub struct Verible {\n    pub syntax: VeribleSyntax,\n    pub format: VeribleFormat,\n}\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(default)]\npub struct VeribleSyntax {\n    pub enabled: bool,\n    pub path: String,\n    pub args: Vec<String>,\n}\n\nimpl Default for VeribleSyntax {\n    fn default() -> Self {\n        Self {\n            enabled: true,\n            path: \"verible-verilog-syntax\".to_string(),\n            args: Vec::new(),\n        }\n    }\n}\n\n#[derive(Debug, Default, Serialize, Deserialize)]\n#[serde(default)]\npub struct Verilator {\n    pub syntax: VerilatorSyntax,\n}\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(default)]\npub struct VerilatorSyntax {\n    pub enabled: bool,\n    pub path: String,\n    pub args: Vec<String>,\n}\n\nimpl Default for VerilatorSyntax {\n    fn default() -> Self {\n        Self {\n            enabled: true,\n            path: \"verilator\".to_string(),\n            args: vec![\n                \"--lint-only\".to_string(),\n                \"--sv\".to_string(),\n                \"-Wall\".to_string(),\n            ],\n        }\n    }\n}\n\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(default)]\npub struct VeribleFormat {\n    pub enabled: bool,\n    pub path: String,\n    pub args: Vec<String>,\n}\n\nimpl Default for VeribleFormat {\n    fn default() -> Self {\n        Self {\n            enabled: true,\n            path: \"verible-verilog-format\".to_string(),\n            args: Vec::new(),\n        }\n    }\n}\n\nfn read_config(root_uri: Option<Url>) -> anyhow::Result<ProjectConfig> {\n    let path = root_uri\n        .ok_or_else(|| anyhow::anyhow!(\"couldn't resolve workdir path\"))?\n        .to_file_path()\n        .map_err(|_| anyhow::anyhow!(\"couldn't resolve workdir path\"))?;\n    let mut config: Option<PathBuf> = None;\n    for dir in path.ancestors() {\n        let config_path = dir.join(\"veridian.yaml\");\n        if config_path.exists() {\n            info!(\"found config: veridian.yaml\");\n            config = Some(config_path);\n            break;\n        }\n        let config_path = dir.join(\"veridian.yml\");\n        if config_path.exists() {\n            info!(\"found config: veridian.yml\");\n            config = Some(config_path);\n            break;\n        }\n    }\n    let mut contents = String::new();\n    File::open(config.ok_or_else(|| anyhow::anyhow!(\"unable to read config file\"))?)?\n        .read_to_string(&mut contents)?;\n    info!(\"reading config file\");\n    Ok(serde_yaml::from_str(&contents)?)\n}\n\n// convert string path to absolute path\nfn absolute_path(path_str: &str) -> Option<PathBuf> {\n    let path = PathBuf::from(path_str);\n    if !path.exists() {\n        return None;\n    }\n    if !path.has_root() {\n        Some(current_dir().unwrap().join(path).clean())\n    } else {\n        Some(path)\n    }\n}\n\n#[tower_lsp::async_trait]\nimpl LanguageServer for Backend {\n    async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {\n        // grab include dirs and source dirs from config, and convert to abs path\n        let mut inc_dirs = self.server.srcs.include_dirs.write().unwrap();\n        let mut src_dirs = self.server.srcs.source_dirs.write().unwrap();\n        match read_config(params.root_uri) {\n            Ok(conf) => {\n                inc_dirs.extend(conf.include_dirs.iter().filter_map(|x| absolute_path(x)));\n                debug!(\"{:#?}\", inc_dirs);\n                src_dirs.extend(conf.source_dirs.iter().filter_map(|x| absolute_path(x)));\n                debug!(\"{:#?}\", src_dirs);\n                let mut log_handle = self.server.log_handle.lock().unwrap();\n                let log_handle = log_handle.as_mut();\n                if let Some(handle) = log_handle {\n                    handle\n                        .parse_and_push_temp_spec(conf.log_level.to_string())\n                        .map_err(|e| Error {\n                            code: ErrorCode::InvalidParams,\n                            message: e.to_string().into(),\n                            data: None,\n                        })?;\n                }\n                *self.server.conf.write().unwrap() = conf;\n            }\n            Err(e) => {\n                warn!(\"found errors in config file: {:#?}\", e);\n            }\n        }\n        let mut conf = self.server.conf.write().unwrap();\n        conf.verible.syntax.enabled = which(&conf.verible.syntax.path).is_ok();\n        if cfg!(feature = \"slang\") {\n            info!(\"enabled linting with slang\");\n        }\n        if conf.verilator.syntax.enabled {\n            info!(\"enabled linting with verilator\")\n        } else if conf.verible.syntax.enabled {\n            info!(\"enabled linting with verible-verilog-syntax\")\n        }\n        conf.verible.format.enabled = which(&conf.verible.format.path).is_ok();\n        if conf.verible.format.enabled {\n            info!(\"enabled formatting with verible-verilog-format\");\n        } else {\n            info!(\"formatting unavailable\");\n        }\n        drop(inc_dirs);\n        drop(src_dirs);\n        // parse all source files found from walking source dirs and include dirs\n        self.server.srcs.init();\n        Ok(InitializeResult {\n            server_info: None,\n            capabilities: ServerCapabilities {\n                text_document_sync: Some(TextDocumentSyncCapability::Options(\n                    TextDocumentSyncOptions {\n                        open_close: Some(true),\n                        change: Some(TextDocumentSyncKind::INCREMENTAL),\n                        will_save: None,\n                        will_save_wait_until: None,\n                        save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions {\n                            include_text: None,\n                        })),\n                    },\n                )),\n                completion_provider: Some(CompletionOptions {\n                    resolve_provider: Some(false),\n                    trigger_characters: Some(vec![\n                        \".\".to_string(),\n                        \"$\".to_string(),\n                        \"`\".to_string(),\n                    ]),\n                    work_done_progress_options: WorkDoneProgressOptions {\n                        work_done_progress: None,\n                    },\n                    all_commit_characters: None,\n                    //TODO: check if corect\n                    completion_item: None,\n                }),\n                definition_provider: Some(OneOf::Left(true)),\n                hover_provider: Some(HoverProviderCapability::Simple(true)),\n                document_symbol_provider: Some(OneOf::Left(true)),\n                document_formatting_provider: Some(OneOf::Left(conf.verible.format.enabled)),\n                document_range_formatting_provider: Some(OneOf::Left(conf.verible.format.enabled)),\n                document_highlight_provider: Some(OneOf::Left(true)),\n                ..ServerCapabilities::default()\n            },\n        })\n    }\n    async fn initialized(&self, _: InitializedParams) {\n        self.client\n            .log_message(MessageType::INFO, \"veridian initialized!\")\n            .await;\n    }\n    async fn shutdown(&self) -> Result<()> {\n        Ok(())\n    }\n    async fn did_open(&self, params: DidOpenTextDocumentParams) {\n        let diagnostics = self.server.did_open(params);\n        self.client\n            .publish_diagnostics(\n                diagnostics.uri,\n                diagnostics.diagnostics,\n                diagnostics.version,\n            )\n            .await;\n    }\n    async fn did_change(&self, params: DidChangeTextDocumentParams) {\n        self.server.did_change(params);\n    }\n    async fn did_save(&self, params: DidSaveTextDocumentParams) {\n        let diagnostics = self.server.did_save(params);\n        self.client\n            .publish_diagnostics(\n                diagnostics.uri,\n                diagnostics.diagnostics,\n                diagnostics.version,\n            )\n            .await;\n    }\n    async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {\n        Ok(self.server.completion(params))\n    }\n    async fn goto_definition(\n        &self,\n        params: GotoDefinitionParams,\n    ) -> Result<Option<GotoDefinitionResponse>> {\n        Ok(self.server.goto_definition(params))\n    }\n    async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {\n        Ok(self.server.hover(params))\n    }\n    async fn document_symbol(\n        &self,\n        params: DocumentSymbolParams,\n    ) -> Result<Option<DocumentSymbolResponse>> {\n        Ok(self.server.document_symbol(params))\n    }\n    async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {\n        Ok(self.server.formatting(params))\n    }\n    async fn range_formatting(\n        &self,\n        params: DocumentRangeFormattingParams,\n    ) -> Result<Option<Vec<TextEdit>>> {\n        Ok(self.server.range_formatting(params))\n    }\n    async fn document_highlight(\n        &self,\n        params: DocumentHighlightParams,\n    ) -> Result<Option<Vec<DocumentHighlight>>> {\n        Ok(self.server.document_highlight(params))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_config() {\n        let config = r#\"\nauto_search_workdir: false\nformat: true\nverible:\n  syntax:\n    enabled: true\n    path: \"verible-verilog-syntax\"\n  format:\n    args:\n      - --net_variable_alignment=align\nlog_level: Info\n\"#;\n        let config = serde_yaml::from_str::<ProjectConfig>(config);\n        dbg!(&config);\n        assert!(config.is_ok());\n    }\n}\n"
  },
  {
    "path": "src/sources.rs",
    "content": "use crate::definition::def_types::*;\nuse crate::definition::get_scopes;\nuse crate::diagnostics::{get_diagnostics, is_hidden};\nuse crate::server::LSPServer;\nuse log::{debug, error, trace};\nuse pathdiff::diff_paths;\nuse ropey::{Rope, RopeSlice};\nuse std::cmp::min;\nuse std::collections::HashMap;\nuse std::env::current_dir;\nuse std::fs;\nuse std::ops::Range as StdRange;\nuse std::path::PathBuf;\nuse std::sync::{Arc, Condvar, Mutex, RwLock};\nuse std::thread;\nuse std::time::Instant;\nuse sv_parser::*;\nuse tower_lsp::lsp_types::*;\nuse walkdir::WalkDir;\n\nimpl LSPServer {\n    pub fn did_open(&self, params: DidOpenTextDocumentParams) -> PublishDiagnosticsParams {\n        let document: TextDocumentItem = params.text_document;\n        let uri = document.uri.clone();\n        debug!(\"did_open: {}\", &uri);\n        // check if doc is already added\n        if self.srcs.names.read().unwrap().contains_key(&document.uri) {\n            // convert to a did_change that replace the entire text\n            self.did_change(DidChangeTextDocumentParams {\n                text_document: VersionedTextDocumentIdentifier::new(document.uri, document.version),\n                content_changes: vec![TextDocumentContentChangeEvent {\n                    range: None,\n                    range_length: None,\n                    text: document.text,\n                }],\n            });\n        } else {\n            self.srcs.add(document);\n        }\n        // diagnostics\n        let urls = self.srcs.names.read().unwrap().keys().cloned().collect();\n        let file_id = self.srcs.get_id(&uri);\n        let file = self.srcs.get_file(file_id).unwrap();\n        let file = file.read().unwrap();\n        get_diagnostics(uri, &file.text, urls, &self.conf.read().unwrap())\n    }\n\n    pub fn did_change(&self, params: DidChangeTextDocumentParams) {\n        debug!(\"did_change: {}\", &params.text_document.uri);\n        let file_id = self.srcs.get_id(&params.text_document.uri);\n        let file = self.srcs.get_file(file_id).unwrap();\n        let mut file = file.write().unwrap();\n        // loop through changes and apply\n        for change in params.content_changes {\n            if change.range.is_none() {\n                file.text = Rope::from_str(&change.text);\n            } else {\n                file.text.apply_change(&change);\n            }\n            file.last_change_range = change.range;\n        }\n        file.version = params.text_document.version;\n        drop(file);\n\n        // invalidate syntaxtree and wake parse thread\n        let meta_data = self.srcs.get_meta_data(file_id).unwrap();\n        let (lock, cvar) = &*meta_data.read().unwrap().valid_parse;\n        let mut valid = lock.lock().unwrap();\n        *valid = false;\n        cvar.notify_all();\n    }\n\n    pub fn did_save(&self, params: DidSaveTextDocumentParams) -> PublishDiagnosticsParams {\n        let urls = self.srcs.names.read().unwrap().keys().cloned().collect();\n        let file_id = self.srcs.get_id(&params.text_document.uri);\n        let file = self.srcs.get_file(file_id).unwrap();\n        let file = file.read().unwrap();\n        get_diagnostics(\n            params.text_document.uri,\n            &file.text,\n            urls,\n            &self.conf.read().unwrap(),\n        )\n    }\n}\n\n/// The Source struct holds all file specific information\npub struct Source {\n    pub id: usize,\n    pub uri: Url,\n    pub text: Rope,\n    pub version: i32,\n    pub syntax_tree: Option<SyntaxTree>,\n    // if there is a parse error, we can remove the last change\n    pub last_change_range: Option<Range>,\n}\n\n/// file metadata, including whether or not the syntax tree is up to date\npub struct SourceMeta {\n    pub id: usize,\n    pub valid_parse: Arc<(Mutex<bool>, Condvar)>,\n}\n\n/// find SystemVerilog/Verilog sources recursively from opened files\nfn find_src_paths(dirs: &[PathBuf]) -> Vec<PathBuf> {\n    let mut paths: Vec<PathBuf> = Vec::new();\n\n    for dir in dirs {\n        let walker = WalkDir::new(dir).into_iter();\n        for entry in walker.filter_entry(|e| !is_hidden(e)) {\n            let entry = entry.unwrap();\n            if entry.file_type().is_file() && entry.path().extension().is_some() {\n                let extension = entry.path().extension().unwrap();\n\n                if extension == \"sv\" || extension == \"svh\" || extension == \"v\" || extension == \"vh\"\n                {\n                    let entry_path = entry.path().to_path_buf();\n                    if !paths.contains(&entry_path) {\n                        paths.push(entry_path);\n                    }\n                }\n            }\n        }\n    }\n    paths\n}\n\n/// The Sources struct manages all source files\npub struct Sources {\n    // all files\n    pub files: Arc<RwLock<Vec<Arc<RwLock<Source>>>>>,\n    // map file urls to id\n    pub names: Arc<RwLock<HashMap<Url, usize>>>,\n    // file metadata\n    pub meta: Arc<RwLock<Vec<Arc<RwLock<SourceMeta>>>>>,\n    // all source files are indexed into this tree, which can then\n    // be used for completion, name resolution\n    pub scope_tree: Arc<RwLock<Option<GenericScope>>>,\n    // include directories, passed to parser to resolve `include\n    pub include_dirs: Arc<RwLock<Vec<PathBuf>>>,\n    // source directories\n    pub source_dirs: Arc<RwLock<Vec<PathBuf>>>,\n}\n\nimpl std::default::Default for Sources {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Sources {\n    pub fn new() -> Self {\n        Self {\n            files: Arc::new(RwLock::new(Vec::new())),\n            names: Arc::new(RwLock::new(HashMap::new())),\n            meta: Arc::new(RwLock::new(Vec::new())),\n            scope_tree: Arc::new(RwLock::new(None)),\n            include_dirs: Arc::new(RwLock::new(Vec::new())),\n            source_dirs: Arc::new(RwLock::new(Vec::new())),\n        }\n    }\n    pub fn init(&self) {\n        let mut paths: Vec<PathBuf> = Vec::new();\n        for path in &*self.include_dirs.read().unwrap() {\n            paths.push(path.clone());\n        }\n        for path in &*self.source_dirs.read().unwrap() {\n            paths.push(path.clone());\n        }\n        // find and add all source/header files recursively from configured include and source directories\n        let src_paths = find_src_paths(&paths);\n        for path in src_paths {\n            if let Ok(url) = Url::from_file_path(&path) {\n                if let Ok(text) = fs::read_to_string(&path) {\n                    self.add(TextDocumentItem::new(\n                        url,\n                        \"systemverilog\".to_string(),\n                        -1,\n                        text,\n                    ));\n                }\n            }\n        }\n    }\n\n    /// add a source file, creating a parse thread for that file\n    pub fn add(&self, doc: TextDocumentItem) {\n        // use a condvar to synchronize the parse thread\n        // the valid bool decides whether or not the file\n        // needs to be re-parsed\n        #[allow(clippy::mutex_atomic)] // https://github.com/rust-lang/rust-clippy/issues/1516\n        let valid_parse = Arc::new((Mutex::new(false), Condvar::new()));\n        let valid_parse2 = valid_parse.clone();\n        let mut files = self.files.write().unwrap();\n        let source = Arc::new(RwLock::new(Source {\n            id: files.len(),\n            uri: doc.uri.clone(),\n            text: Rope::from_str(&doc.text),\n            version: doc.version,\n            syntax_tree: None,\n            last_change_range: None,\n        }));\n        let source_handle = source.clone();\n        let scope_handle = self.scope_tree.clone();\n        let inc_dirs = self.include_dirs.clone();\n\n        // spawn parse thread\n        let _ = thread::spawn(move || {\n            let (lock, cvar) = &*valid_parse2;\n            loop {\n                let now = Instant::now();\n                let file = source_handle.read().unwrap();\n                let text = file.text.clone();\n                let uri = &file.uri.clone();\n                let range = &file.last_change_range.clone();\n                drop(file);\n                trace!(\"{}, parse read: {}\", uri, now.elapsed().as_millis());\n                let syntax_tree = parse(&text, uri, range, &inc_dirs.read().unwrap());\n                let mut scope_tree = match &syntax_tree {\n                    Some(tree) => get_scopes(tree, uri),\n                    None => None,\n                };\n                trace!(\n                    \"{}, parse read complete: {}\",\n                    uri,\n                    now.elapsed().as_millis()\n                );\n                let mut file = source_handle.write().unwrap();\n                trace!(\"{}, parse write: {}\", uri, now.elapsed().as_millis());\n                file.syntax_tree = syntax_tree;\n                drop(file);\n                debug!(\"try write global scope\");\n                let mut global_scope = scope_handle.write().unwrap();\n                match &mut *global_scope {\n                    Some(scope) => {\n                        if let Some(tree) = &mut scope_tree {\n                            scope.defs.retain(|x| &x.url() != uri);\n                            scope.scopes.retain(|x| &x.url() != uri);\n                            scope.defs.append(&mut tree.defs);\n                            scope.scopes.append(&mut tree.scopes);\n                        }\n                    }\n                    None => *global_scope = scope_tree,\n                }\n                // eprintln!(\"{:#?}\", *global_scope);\n                drop(global_scope);\n                trace!(\"{}, write global scope\", uri);\n                trace!(\n                    \"{}, parse write complete: {}\",\n                    uri,\n                    now.elapsed().as_millis()\n                );\n                let mut valid = lock.lock().unwrap();\n                *valid = true;\n                cvar.notify_all();\n                while *valid {\n                    valid = cvar.wait(valid).unwrap();\n                }\n            }\n        });\n        files.push(source);\n        let fid = files.len() - 1;\n        self.meta\n            .write()\n            .unwrap()\n            .push(Arc::new(RwLock::new(SourceMeta {\n                id: fid,\n                valid_parse,\n            })));\n        debug!(\"added {}\", &doc.uri);\n        self.names.write().unwrap().insert(doc.uri, fid);\n    }\n\n    /// get file by id\n    pub fn get_file(&self, id: usize) -> Option<Arc<RwLock<Source>>> {\n        let files = self.files.read().ok()?;\n        for file in files.iter() {\n            let source = file.read().ok()?;\n            if source.id == id {\n                return Some(file.clone());\n            }\n        }\n        None\n    }\n\n    /// get metadata by file id\n    pub fn get_meta_data(&self, id: usize) -> Option<Arc<RwLock<SourceMeta>>> {\n        let meta = self.meta.read().ok()?;\n        for data in meta.iter() {\n            let i = data.read().ok()?;\n            if i.id == id {\n                return Some(data.clone());\n            }\n        }\n        None\n    }\n\n    /// wait for a valid parse\n    pub fn wait_parse_ready(&self, id: usize, wait_valid: bool) {\n        let file = self.get_file(id).unwrap();\n        let file = file.read().unwrap();\n        if file.syntax_tree.is_none() || wait_valid {\n            drop(file);\n            let meta_data = self.get_meta_data(id).unwrap();\n            let (lock, cvar) = &*meta_data.read().unwrap().valid_parse;\n            let mut valid = lock.lock().unwrap();\n            while !*valid {\n                valid = cvar.wait(valid).unwrap();\n            }\n        }\n    }\n\n    /// get file id from url\n    pub fn get_id(&self, uri: &Url) -> usize {\n        *self.names.read().unwrap().get(uri).unwrap()\n    }\n\n    /// compute identifier completions\n    pub fn get_completions(\n        &self,\n        token: &str,\n        byte_idx: usize,\n        url: &Url,\n    ) -> Option<CompletionList> {\n        debug!(\"retrieving identifier completion for token: {}\", &token);\n        Some(CompletionList {\n            is_incomplete: false,\n            items: self\n                .scope_tree\n                .read()\n                .ok()?\n                .as_ref()?\n                .get_completion(token, byte_idx, url),\n        })\n    }\n\n    /// compute dot completions\n    pub fn get_dot_completions(\n        &self,\n        token: &str,\n        byte_idx: usize,\n        url: &Url,\n    ) -> Option<CompletionList> {\n        debug!(\"retrieving dot completion for token: {}\", &token);\n        let tree = self.scope_tree.read().ok()?;\n        Some(CompletionList {\n            is_incomplete: false,\n            items: tree\n                .as_ref()?\n                .get_dot_completion(token, byte_idx, url, tree.as_ref()?),\n        })\n    }\n}\n\n//TODO: show all unrecoverable parse errors to user\n/// parse the file using sv-parser, attempt to recover if the parse fails\npub fn parse(\n    doc: &Rope,\n    uri: &Url,\n    last_change_range: &Option<Range>,\n    inc_paths: &[PathBuf],\n) -> Option<SyntaxTree> {\n    let mut parse_iterations = 1;\n    let mut i = 0;\n    let mut includes: Vec<PathBuf> = inc_paths.to_vec();\n    let mut reverted_change = false;\n    let mut text = doc.clone();\n\n    while i < parse_iterations {\n        i += 1;\n        match parse_sv_str(\n            &text.to_string(),\n            uri.to_file_path().unwrap(),\n            &HashMap::new(),\n            &includes,\n            false,\n        ) {\n            Ok((syntax_tree, _)) => {\n                debug!(\"parse complete of {}\", uri);\n                trace!(\"{}\", syntax_tree.to_string());\n                return Some(syntax_tree);\n            }\n            Err(err) => {\n                match err {\n                    // syntax error\n                    sv_parser::Error::Parse(trace) => match trace {\n                        Some((_, bpos)) => {\n                            let mut line_start = text.byte_to_line(bpos);\n                            let mut line_end = text.byte_to_line(bpos) + 1;\n                            if !reverted_change {\n                                if let Some(range) = last_change_range {\n                                    line_start = range.start.line as usize;\n                                    line_end = range.end.line as usize + 1;\n                                    reverted_change = true;\n                                }\n                            }\n                            for line_idx in line_start..line_end {\n                                let line = text.line(line_idx);\n                                let start_char = text.line_to_char(line_idx);\n                                let line_length = line.len_chars();\n                                text.remove(start_char..(start_char + line_length - 1));\n                                text.insert(start_char, &\" \".to_owned().repeat(line_length));\n                            }\n                            parse_iterations += 1;\n                        }\n                        None => return None,\n                    },\n                    // include error, take the include path from the error message and\n                    // add it as an include dir for the next parser invocation\n                    sv_parser::Error::Include { source: x } => {\n                        if let sv_parser::Error::File { source: _, path: z } = *x {\n                            // Include paths have to be relative to the working directory\n                            // so we have to convert a source file relative path to a working directory\n                            // relative path. This should have been handled by sv-parser\n                            let mut inc_path_given = z.clone();\n                            let mut uri_path = uri.to_file_path().unwrap();\n                            uri_path.pop();\n                            let rel_path = diff_paths(uri_path, current_dir().unwrap()).unwrap();\n                            inc_path_given.pop();\n                            let inc_path = rel_path.join(inc_path_given);\n                            if !includes.contains(&inc_path) {\n                                includes.push(inc_path);\n                            } else {\n                                error!(\"parser: include error: {:?}\", z);\n                                break;\n                            }\n                            parse_iterations += 1;\n                        }\n                    }\n                    _ => error!(\"parse error, {:?}\", err),\n                };\n            }\n        }\n    }\n    None\n}\n\n//TODO: add bounds checking for utf8<->utf16 conversions\n/// This trait defines some helper functions to convert between lsp types\n/// and char/byte positions\npub trait LSPSupport {\n    fn pos_to_byte(&self, pos: &Position) -> usize;\n    fn pos_to_char(&self, pos: &Position) -> usize;\n    fn byte_to_pos(&self, byte_idx: usize) -> Position;\n    fn char_to_pos(&self, char_idx: usize) -> Position;\n    fn range_to_char_range(&self, range: &Range) -> StdRange<usize>;\n    fn char_range_to_range(&self, range: StdRange<usize>) -> Range;\n    fn apply_change(&mut self, change: &TextDocumentContentChangeEvent);\n}\n\n/// Extend ropey's Rope type with lsp convenience functions\nimpl LSPSupport for Rope {\n    fn pos_to_byte(&self, pos: &Position) -> usize {\n        self.char_to_byte(self.pos_to_char(pos))\n    }\n    fn pos_to_char(&self, pos: &Position) -> usize {\n        let line_slice = self.line(pos.line as usize);\n        self.line_to_char(pos.line as usize) + line_slice.utf16_cu_to_char(pos.character as usize)\n    }\n    fn byte_to_pos(&self, byte_idx: usize) -> Position {\n        self.char_to_pos(self.byte_to_char(min(byte_idx, self.len_bytes() - 1)))\n    }\n    fn char_to_pos(&self, char_idx: usize) -> Position {\n        let line = self.char_to_line(char_idx);\n        let line_slice = self.line(line);\n        Position {\n            line: line as u32,\n            character: line_slice.char_to_utf16_cu(char_idx - self.line_to_char(line)) as u32,\n        }\n    }\n    fn range_to_char_range(&self, range: &Range) -> StdRange<usize> {\n        self.pos_to_char(&range.start)..self.pos_to_char(&range.end)\n    }\n    fn char_range_to_range(&self, range: StdRange<usize>) -> Range {\n        Range {\n            start: self.char_to_pos(range.start),\n            end: self.char_to_pos(range.end),\n        }\n    }\n    fn apply_change(&mut self, change: &TextDocumentContentChangeEvent) {\n        if let Some(range) = change.range {\n            let char_range = self.range_to_char_range(&range);\n            self.remove(char_range.clone());\n            if !change.text.is_empty() {\n                self.insert(char_range.start, &change.text);\n            }\n        }\n    }\n}\n\nimpl LSPSupport for RopeSlice<'_> {\n    fn pos_to_byte(&self, pos: &Position) -> usize {\n        self.char_to_byte(self.pos_to_char(pos))\n    }\n    fn pos_to_char(&self, pos: &Position) -> usize {\n        let line_slice = self.line(pos.line as usize);\n        self.line_to_char(pos.line as usize) + line_slice.utf16_cu_to_char(pos.character as usize)\n    }\n    fn byte_to_pos(&self, byte_idx: usize) -> Position {\n        self.char_to_pos(self.byte_to_char(min(byte_idx, self.len_bytes() - 1)))\n    }\n    fn char_to_pos(&self, char_idx: usize) -> Position {\n        let line = self.char_to_line(char_idx);\n        let line_slice = self.line(line);\n        Position {\n            line: line as u32,\n            character: line_slice.char_to_utf16_cu(char_idx - self.line_to_char(line)) as u32,\n        }\n    }\n    fn range_to_char_range(&self, range: &Range) -> StdRange<usize> {\n        self.pos_to_char(&range.start)..self.pos_to_char(&range.end)\n    }\n    fn char_range_to_range(&self, range: StdRange<usize>) -> Range {\n        Range {\n            start: self.char_to_pos(range.start),\n            end: self.char_to_pos(range.end),\n        }\n    }\n    fn apply_change(&mut self, _: &TextDocumentContentChangeEvent) {\n        panic!(\"can't edit a rope slice\");\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::support::test_init;\n    use std::fs::read_to_string;\n\n    #[test]\n    fn test_open_and_change() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"module test;\n  logic abc;\nendmodule\"#;\n\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n        let file = server.srcs.get_file(fid).unwrap();\n        let file = file.read().unwrap();\n        assert_eq!(file.text.to_string(), text.to_owned());\n        drop(file);\n\n        let change_params = DidChangeTextDocumentParams {\n            text_document: VersionedTextDocumentIdentifier { uri, version: 1 },\n            content_changes: vec![TextDocumentContentChangeEvent {\n                range: Some(Range {\n                    start: Position {\n                        line: 1,\n                        character: 8,\n                    },\n                    end: Position {\n                        line: 1,\n                        character: 11,\n                    },\n                }),\n                range_length: None,\n                text: \"var1\".to_owned(),\n            }],\n        };\n        server.did_change(change_params);\n        let file = server.srcs.get_file(fid).unwrap();\n        let file = file.read().unwrap();\n        assert_eq!(\n            file.text.to_string(),\n            r#\"module test;\n  logic var1;\nendmodule\"#\n                .to_owned()\n        );\n        assert_eq!(file.version, 1);\n    }\n\n    #[test]\n    fn test_fault_tolerance() {\n        test_init();\n        let server = LSPServer::new(None);\n        let uri = Url::parse(\"file:///test.sv\").unwrap();\n        let text = r#\"module test;\n  logic abc\nendmodule\"#;\n        let open_params = DidOpenTextDocumentParams {\n            text_document: TextDocumentItem {\n                uri: uri.clone(),\n                language_id: \"systemverilog\".to_owned(),\n                version: 0,\n                text: text.to_owned(),\n            },\n        };\n        server.did_open(open_params);\n        let fid = server.srcs.get_id(&uri);\n\n        server.srcs.wait_parse_ready(fid, true);\n\n        assert!(server\n            .srcs\n            .scope_tree\n            .read()\n            .unwrap()\n            .as_ref()\n            .unwrap()\n            .contains_scope(\"test\"));\n    }\n\n    #[test]\n    fn test_header() {\n        test_init();\n        let mut d = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));\n        d.push(\"test_data/top_inc.sv\");\n        let text = read_to_string(&d).unwrap();\n        let doc = Rope::from_str(&text);\n        assert!(parse(&doc, &Url::from_file_path(d).unwrap(), &None, &Vec::new()).is_some(),);\n        // TODO: add missing header test\n    }\n}\n"
  },
  {
    "path": "src/support.rs",
    "content": "pub fn test_init() {\n    let _ = flexi_logger::Logger::with(flexi_logger::LogSpecification::info()).start();\n}\n"
  },
  {
    "path": "test_data/complete.sv",
    "content": "interface test(logic clk);\n    logic a;\n    logic b;\n    modport in (input clk, a , b);\n    modport out (output clk, a, b);\nendinterface\n\nmodule test1(\n    test.in tinter,\n    test interb\n);\nendmodule\n"
  },
  {
    "path": "test_data/definition_test.sv",
    "content": "interface simple_bus (input logic clk); // Define the interface\n    logic req, gnt;\n    logic [7:0] addr, data;\n    logic [1:0] mode;\n    logic start, rdy;\n    modport slave( input req, addr, mode, start, clk,\n                   output gnt, rdy,\n                   ref data,\n                   export Read, Write);\n    modport master(input gnt, rdy, clk,\n                   output req, addr, mode, start,\n                   ref data,\n                   import task Read(input logic [7:0] raddr),\n                   task Write(input logic [7:0] waddr));\nendinterface: simple_bus\n\nmodule test;\n    logic clk;\n    simple_bus bus (.*);\nendmodule\n"
  },
  {
    "path": "test_data/diag/diag_test.sv",
    "content": "module test;\n  logic [1:0] abc;\n\n  assign abc[2] = 1'b0;\nendmodule\n"
  },
  {
    "path": "test_data/ind.sv",
    "content": "module test;\n    logic abc;\n    logic abcd;\n\n  a\nendmodule\n\n"
  },
  {
    "path": "test_data/interface_obj.sv",
    "content": "interface ebus_i;\n    integer I;\n    // reference to I not allowed through modport mp\n    typedef enum {Y,N} choice;\n    choice Q;\n    localparam True = 1;\n    modport mp(input Q);\nendinterface\n\nmodule Top;\n    ebus_i ebus ();\n    sub s1 (ebus.mp);\nendmodule\n\nmodule sub(ebus_i.mp i);\n    typedef i.choice yes_no;\n    yes_no P;\n    assign P = i.Q;\n    initial\n    Top.ebus.Q = i.True;\n    initial\n    Top.ebus.I = 0;\nendmodule\n"
  },
  {
    "path": "test_data/simple_bus.svh",
    "content": "interface simple_bus (input logic clk); // Define the interface\n    logic req, gnt;\n    logic [7:0] addr, data;\n    logic [1:0] mode;\n    logic start, rdy;\n    modport slave( input req, addr, mode, start, clk,\n                   output gnt, rdy,\n                   ref data,\n                   export Read, Write);\n    modport master(input gnt, rdy, clk,\n                   output req, addr, mode, start,\n                   ref data,\n                   import task Read(input logic [7:0] raddr),\n                   task Write(input logic [7:0] waddr));\nendinterface: simple_bus\n"
  },
  {
    "path": "test_data/test_inter.sv",
    "content": "interface simple_bus;\n    logic clk;\nendinterface\n\nmodule test2;\n    simple_bus b ();\nendmodule\n"
  },
  {
    "path": "test_data/top.sv",
    "content": "module test;\n    simple_bus bus ();\nendmodule\n"
  },
  {
    "path": "test_data/top_inc.sv",
    "content": "`timescale 1ns/1ps\n`include \"simple_bus.svh\"\n\nmodule test;\n    simple_bus bus ();\nendmodule\n"
  },
  {
    "path": "test_data/verilator_errors.txt",
    "content": "%Error: test.sv:6: syntax error, unexpected endmodule, expecting IDENTIFIER endmodule\n%Error: test.sv:6:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize\n%Error: test.sv:6:1: syntax error, unexpected endmodule, expecting IDENTIFIER or '(' or randomize\n%Warning-ALWCOMBORDER: test.sv:5:4: Always_comb variable driven after use: 'b'\n%Error: test2.sv:6:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize\n"
  },
  {
    "path": "veridian-slang/Cargo.toml",
    "content": "[package]\nname = \"veridian_slang\"\nversion = \"0.1.0\"\nauthors = [\"Vivek Malneedi <vivekmalneedi@gmail.com>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n\n[build-dependencies]\nbindgen = \"0.71.1\"\nreqwest = { version = \"0.12.4\", features = [\"blocking\"] }\nflate2 = \"1.0.20\"\ntar = \"0.4.35\"\ncmake = \"0.1.50\"\n\n[dev-dependencies]\ntempdir = \"0.3.7\"\nserial_test = \"3.2.0\"\n"
  },
  {
    "path": "veridian-slang/build.rs",
    "content": "use flate2::read::GzDecoder;\nuse std::env;\nuse std::fs::{self, File};\nuse std::path::{Path, PathBuf};\nuse tar::Archive;\n\ntype Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;\n\nfn download_slang(download_to: &Path) -> Result<PathBuf> {\n    // Keep the version the same as the one in `CMakeLists.txt`\n    let target = \"https://github.com/MikePopoloski/slang/archive/refs/tags/v9.1.tar.gz\";\n\n    fs::create_dir_all(download_to)?;\n\n    // Download source\n    let archive_path = download_to.join(\"slang-linux.tar.gz\");\n    let mut dest = File::create(&archive_path)?;\n    reqwest::blocking::get(target)?.copy_to(&mut dest)?;\n    drop(dest);\n\n    // Unpack archive\n    let mut archive = Archive::new(GzDecoder::new(File::open(archive_path)?));\n    archive.unpack(download_to)?;\n\n    // Return the source directory\n    let entries = fs::read_dir(&download_to)?\n        .filter_map(|entry| entry.ok())\n        .filter(|entry| entry.metadata().is_ok_and(|e| e.is_dir()))\n        .collect::<Vec<_>>();\n    // Expected exactly one directory in archive\n    assert_eq!(entries.len(), 1);\n    Ok(entries.first().unwrap().path())\n}\n\nfn build_slang(slang_src: &Path, slang_install: &Path) {\n    cmake::Config::new(slang_src)\n        .profile(\"Release\")\n        .define(\"SLANG_USE_MIMALLOC\", \"OFF\")\n        .out_dir(slang_install)\n        .build();\n}\n\nfn build_slang_wrapper(slang: &Path, wrapper_install: &Path) {\n    cmake::Config::new(\"slang_wrapper\")\n        .profile(\"Release\")\n        .define(\"CMAKE_PREFIX_PATH\", slang)\n        .out_dir(wrapper_install)\n        .build();\n}\n\nfn main() -> Result<()> {\n    let out_dir = PathBuf::from(env::var(\"OUT_DIR\")?);\n    println!(\"cargo:rerun-if-changed=slang_wrapper\");\n\n    let (slang_install, wrapper_install, link_type) = match env::var(\"SLANG_INSTALL_PATH\") {\n        Err(_) => {\n            // Build slang from source\n            let download_dir = out_dir.join(\"slang-src\");\n            let slang_src = download_slang(&download_dir)?;\n            let slang_install = out_dir.join(\"slang-install\");\n            let wrapper_install = out_dir.join(\"slang-wrapper-install\");\n\n            build_slang(&slang_src, &slang_install);\n            build_slang_wrapper(&slang_install, &wrapper_install);\n\n            (\n                slang_install.join(\"lib\"),\n                wrapper_install.join(\"lib\"),\n                \"static\",\n            )\n        }\n        Ok(slang_install) => {\n            // Directly use external slang\n            let slang_install = Path::new(&slang_install);\n            let wrapper_install = out_dir.join(\"slang-wrapper-install\");\n\n            build_slang_wrapper(slang_install, &wrapper_install);\n\n            (\n                slang_install.join(\"lib\"),\n                wrapper_install.join(\"lib\"),\n                \"dylib\",\n            )\n        }\n    };\n\n    let bindings = bindgen::Builder::default()\n        .clang_arg(\"-x\")\n        .clang_arg(\"c++\")\n        .header(\"slang_wrapper/src/slang_wrapper.h\")\n        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))\n        .generate()\n        .expect(\"Unable to generate bindings\");\n\n    println!(\"cargo:rustc-link-search=native={}\", slang_install.display());\n    println!(\n        \"cargo:rustc-link-search=native={}\",\n        wrapper_install.display()\n    );\n    // println!(\"cargo:rustc-link-search=native=/usr/lib\");\n\n    println!(\"cargo:rustc-link-lib=static=slangwrapper\");\n    println!(\"cargo:rustc-link-lib={link_type}=svlang\");\n    println!(\"cargo:rustc-link-lib=fmt\");\n    println!(\"cargo:rustc-link-lib=dylib=stdc++\");\n\n    bindings\n        .write_to_file(out_dir.join(\"bindings.rs\"))\n        .expect(\"Couldn't write bindings!\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.20)\n\nproject(\n    slang_wrapper\n    LANGUAGES CXX\n)\n\n# Keep the version the same as the one in `build.rs`\nfind_package(slang 9.1 REQUIRED)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nadd_library(\n    slang_wrapper\n    STATIC\n    src/slang_lib.cpp\n    src/basic_client.cpp\n)\ntarget_link_libraries(slang_wrapper PRIVATE slang::slang)\nset_target_properties(slang_wrapper PROPERTIES OUTPUT_NAME \"slangwrapper\")\n\ninstall(\n    TARGETS slang_wrapper\n    LIBRARY DESTINATION lib\n    RUNTIME DESTINATION bin\n)\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/src/BasicClient.h",
    "content": "//------------------------------------------------------------------------------\n//! @file BasicClient.h\n//! @brief Diagnostic client that formats to a text string\n//\n// File is under the MIT license; see LICENSE for details\n//------------------------------------------------------------------------------\n#pragma once\n\n#include <functional>\n#include <string>\n\n#include \"slang/diagnostics/DiagnosticClient.h\"\n\nnamespace slang {\n\nclass FormatBuffer;\nnamespace ast {\n    class Symbol;\n}\n\nclass BasicClient : public DiagnosticClient {\npublic:\n    BasicClient();\n    ~BasicClient();\n\n    void setColorsEnabled(bool enabled);\n\n    template <typename TFunc> void setSymbolPathCB(TFunc&& func) {\n        symbolPathCB = std::forward<TFunc>(func);\n    }\n\n    template <typename TFunc> static void setDefaultSymbolPathCB(TFunc&& func) {\n        defaultSymbolPathCB = std::forward<TFunc>(func);\n    }\n\n    void report(const ReportedDiagnostic& diagnostic) override;\n\n    void clear();\n    std::string getString() const;\n\nprivate:\n    std::unique_ptr<FormatBuffer> buffer;\n\n    using SymbolPathCB = std::function<std::string(const ast::Symbol&)>;\n    SymbolPathCB symbolPathCB;\n    static SymbolPathCB defaultSymbolPathCB;\n\n    void formatDiag(SourceLocation loc, DiagnosticSeverity severity,\n                    std::string_view message, std::string_view optionName);\n};\n\n} // namespace slang\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/src/FormatBuffer.h",
    "content": "//------------------------------------------------------------------------------\n// FormatBuffer.h\n// Internal string formatting helper class\n//\n// File is under the MIT license; see LICENSE for details\n//------------------------------------------------------------------------------\n#pragma once\n\n#include <fmt/color.h>\n#include <fmt/format.h>\n#include <string_view>\n\nnamespace slang {\n\nclass FormatBuffer {\npublic:\n    void append(std::string_view str) { buf.append(str.data(), str.data() + str.size()); }\n\n    void append(const fmt::text_style& style, std::string_view str) { format(style, \"{}\", str); }\n\n    template <typename... Args>\n    void format(fmt::format_string<Args...> format, Args &&...args)\n    {\n        fmt::format_to(fmt::appender(buf), format, std::forward<Args>(args)...);\n    }\n\n    template <typename... Args>\n    void format(const fmt::text_style &style, fmt::format_string<Args...> format, Args &&...args)\n    {\n        if (!showColors) {\n            fmt::format_to(fmt::appender(buf), format, std::forward<Args>(args)...);\n        }\n        else {\n            // TODO: Text style + non-literal string does not compile in fmt 10.2.1, but has been fixed in some commit in the master branch.\n            //       Let's temporarily abandon style to work around it.\n            // fmt::format_to(fmt::appender(buf), style, format, std::forward<Args>(args)...);\n            fmt::format_to(fmt::appender(buf), format, std::forward<Args>(args)...);\n        }\n    }\n\n    size_t size() const { return buf.size(); }\n    const char* data() const { return buf.data(); }\n    char back() const { return buf.data()[buf.size() - 1]; }\n\n    void pop_back() { buf.resize(buf.size() - 1); }\n    void clear() { buf.clear(); }\n    void resize(size_t newSize) { buf.resize(newSize); }\n\n    void setColorsEnabled(bool enabled) { showColors = enabled; }\n\n    std::string str() const { return fmt::to_string(buf); }\n\nprivate:\n    fmt::memory_buffer buf;\n    bool showColors = false;\n};\n\n} // namespace slang\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/src/basic_client.cpp",
    "content": "//------------------------------------------------------------------------------\n// BasicClient.cpp\n// Diagnostic client that formats to a text string\n//\n// File is under the MIT license; see LICENSE for details\n//------------------------------------------------------------------------------\n#include \"BasicClient.h\"\n\n#include \"FormatBuffer.h\"\n\n#include \"slang/text/SourceManager.h\"\n\nnamespace slang {\n\nstatic constexpr auto noteColor = fmt::terminal_color::bright_black;\nstatic constexpr auto warningColor = fmt::terminal_color::bright_yellow;\nstatic constexpr auto errorColor = fmt::terminal_color::bright_red;\nstatic constexpr auto fatalColor = fmt::terminal_color::bright_red;\nstatic constexpr auto highlightColor = fmt::terminal_color::bright_green;\nstatic constexpr auto filenameColor = fmt::terminal_color::cyan;\nstatic constexpr auto locationColor = fmt::terminal_color::bright_cyan;\n\nstatic fmt::terminal_color getSeverityColor(DiagnosticSeverity severity) {\n    switch (severity) {\n    case DiagnosticSeverity::Note: return noteColor;\n    case DiagnosticSeverity::Warning: return warningColor;\n    case DiagnosticSeverity::Error: return errorColor;\n    case DiagnosticSeverity::Fatal: return fatalColor;\n    default: return fmt::terminal_color::black;\n    }\n}\n\nBasicClient::SymbolPathCB BasicClient::defaultSymbolPathCB;\n\nBasicClient::BasicClient()\n    : buffer(std::make_unique<FormatBuffer>()),\n      symbolPathCB(defaultSymbolPathCB) {}\n\nBasicClient::~BasicClient() = default;\n\nvoid BasicClient::setColorsEnabled(bool enabled) {\n    buffer->setColorsEnabled(enabled);\n}\n\nvoid BasicClient::report(const ReportedDiagnostic& diag) {\n    if (diag.shouldShowIncludeStack) {\n        SmallVector<SourceLocation, 8> includeStack;\n        getIncludeStack(diag.location.buffer(), includeStack);\n\n        // Show the stack in reverse.\n        for (int i = int(includeStack.size()) - 1; i >= 0; i--) {\n            SourceLocation loc = includeStack[size_t(i)];\n            buffer->format(\"in file included from {}:{}:\\n\",\n                           sourceManager->getFileName(loc),\n                           sourceManager->getLineNumber(loc));\n        }\n    }\n\n    // Print out the hierarchy where the diagnostic occurred, if we know it.\n    auto& od = diag.originalDiagnostic;\n    if (od.coalesceCount && od.symbol && symbolPathCB) {\n        if (od.coalesceCount == 1)\n            buffer->append(\"  in instance: \"sv);\n        else\n            buffer->format(\"  in {} instances, e.g. \", *od.coalesceCount);\n\n        buffer->append(fmt::emphasis::bold, symbolPathCB(*od.symbol));\n        buffer->append(\"\\n\"sv);\n    }\n\n    // Get all highlight ranges mapped into the reported location of the\n    // diagnostic.\n    SmallVector<SourceRange, 8> mappedRanges;\n    engine->mapSourceRanges(diag.location, diag.ranges, mappedRanges);\n\n    // Write the diagnostic.\n    formatDiag(diag.location, diag.severity, diag.formattedMessage,\n               engine->getOptionName(diag.originalDiagnostic.code));\n\n    // Write out macro expansions, if we have any, in reverse order.\n    for (auto it = diag.expansionLocs.rbegin(); it != diag.expansionLocs.rend();\n         it++) {\n        SourceLocation loc = *it;\n        std::string name(sourceManager->getMacroName(loc));\n        if (name.empty())\n            name = \"expanded from here\";\n        else\n            name = fmt::format(\"expanded from macro '{}'\", name);\n\n        SmallVector<SourceRange, 8> macroRanges;\n        engine->mapSourceRanges(loc, diag.ranges, macroRanges);\n        formatDiag(sourceManager->getFullyOriginalLoc(loc),\n                   DiagnosticSeverity::Note, name, \"\");\n    }\n}\n\nvoid BasicClient::clear() {\n    buffer->clear();\n}\n\nstd::string BasicClient::getString() const {\n    return buffer->str();\n}\n\nvoid BasicClient::formatDiag(SourceLocation loc, DiagnosticSeverity severity,\n                             std::string_view message, std::string_view optionName) {\n    size_t col = 0;\n    if (loc != SourceLocation::NoLocation) {\n        col = sourceManager->getColumnNumber(loc);\n        buffer->append(fg(filenameColor), sourceManager->getFileName(loc));\n        buffer->append(\":\");\n        buffer->format(fg(locationColor), \"{}:{}\",\n                       sourceManager->getLineNumber(loc), col);\n        buffer->append(\": \");\n    }\n\n    buffer->format(fg(getSeverityColor(severity)),\n                   \"{}: \", getSeverityString(severity));\n\n    if (severity != DiagnosticSeverity::Note)\n        buffer->format(fmt::text_style(fmt::emphasis::bold), \"{}\", message);\n    else\n        buffer->append(message);\n\n    if (!optionName.empty())\n        buffer->format(\" [-W{}]\", optionName);\n\n    buffer->append(\"\\n\"sv);\n}\n\n} // namespace slang\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/src/slang_lib.cpp",
    "content": "#include \"BasicClient.h\"\n#include \"slang_wrapper.h\"\n#include <array>\n#include <iostream>\n#include <filesystem>\n#include <fmt/format.h>\n#include <slang/ast/Compilation.h>\n#include <slang/ast/types/TypePrinter.h>\n#include <slang/diagnostics/DiagnosticClient.h>\n#include <slang/diagnostics/DiagnosticEngine.h>\n#include <slang/diagnostics/Diagnostics.h>\n#include <slang/parsing/Preprocessor.h>\n#include <slang/syntax/SyntaxTree.h>\n#include <slang/text/SourceManager.h>\n\nnamespace fs = std::filesystem;\n\nusing namespace slang;\nusing slang::syntax::SyntaxTree;\n\n// Private function\nstatic char* report(const std::string &s) {\n    return strcpy(new char[s.length() + 1], s.c_str());\n}\n\nchar* compile_source(const char* name, const char* text) {\n    Bag options;\n    SourceManager sm;\n    SourceBuffer buffer = sm.assignText(name, text);\n\n    ast::Compilation compilation(options);\n\n    std::array<SourceBuffer, 1> buffers{std::move(buffer)};\n    compilation.addSyntaxTree(SyntaxTree::fromBuffers(buffers, sm, options));\n\n    DiagnosticEngine diagEngine(sm);\n    Diagnostics pragmaDiags = diagEngine.setMappingsFromPragmas();\n\n    auto client = std::make_shared<BasicClient>();\n    client->setColorsEnabled(false);\n    diagEngine.addClient(client);\n\n    for (auto& diag : compilation.getAllDiagnostics()) diagEngine.issue(diag);\n\n    return report(client->getString());\n}\n\nchar* compile_path(const char* path) {\n    Bag options;\n    SourceManager sm;\n    auto buffer = sm.readSource(fs::path{path}, /* library */ nullptr);\n    if (!buffer) {\n        return report(fmt::format(\"'{}': {}\", path, buffer.error().message()));\n    }\n\n    ast::Compilation compilation(options);\n\n    std::array<SourceBuffer, 1> buffers{std::move(*buffer)};\n    compilation.addSyntaxTree(SyntaxTree::fromBuffers(buffers, sm, options));\n\n    DiagnosticEngine diagEngine(sm);\n    Diagnostics pragmaDiags = diagEngine.setMappingsFromPragmas();\n\n    auto client = std::make_shared<BasicClient>();\n    client->setColorsEnabled(false);\n    diagEngine.addClient(client);\n\n    for (auto& diag : compilation.getAllDiagnostics()) diagEngine.issue(diag);\n\n    return report(client->getString());\n}\n\nchar* compile_sources(const char** names, const char** texts,\n                      unsigned int num_files) {\n    Bag options;\n    SourceManager sm;\n    ast::Compilation compilation(options);\n\n    std::vector<SourceBuffer> buffers;\n    buffers.reserve(num_files);\n    for (unsigned int i = 0; i < num_files; i++) {\n        buffers.emplace_back(sm.assignText(names[i], texts[i]));\n    }\n\n    compilation.addSyntaxTree(SyntaxTree::fromBuffers(buffers, sm, options));\n\n    DiagnosticEngine diagEngine(sm);\n    Diagnostics pragmaDiags = diagEngine.setMappingsFromPragmas();\n\n    auto client = std::make_shared<BasicClient>();\n    client->setColorsEnabled(false);\n    diagEngine.addClient(client);\n\n    for (auto& diag : compilation.getAllDiagnostics()) diagEngine.issue(diag);\n\n    return report(client->getString());\n}\n\nchar* compile_paths(const char** paths, unsigned int num_paths) {\n    Bag options;\n    SourceManager sm;\n    ast::Compilation compilation(options);\n\n    std::vector<SourceBuffer> buffers;\n    buffers.reserve(num_paths);\n    for (unsigned int i = 0; i < num_paths; i++) {\n        auto buffer = sm.readSource(fs::path{paths[i]}, /* library */ nullptr);\n        if (!buffer) {\n            return report(fmt::format(\"'{}': {}\", paths[i], buffer.error().message()));\n        }\n        buffers.emplace_back(std::move(*buffer));\n    }\n\n    compilation.addSyntaxTree(SyntaxTree::fromBuffers(buffers, sm, options));\n\n    DiagnosticEngine diagEngine(sm);\n    Diagnostics pragmaDiags = diagEngine.setMappingsFromPragmas();\n\n    auto client = std::make_shared<BasicClient>();\n    client->setColorsEnabled(false);\n    diagEngine.addClient(client);\n\n    for (auto& diag : compilation.getAllDiagnostics()) diagEngine.issue(diag);\n\n    return report(client->getString());\n}\n\nvoid delete_report(char* report) {\n    delete report;\n}\n"
  },
  {
    "path": "veridian-slang/slang_wrapper/src/slang_wrapper.h",
    "content": "#pragma once\n\nextern \"C\" {\nvoid delete_report(char* report);\nchar* compile_source(const char* name, const char* text);\nchar* compile_path(const char* path);\nchar* compile_sources(const char** names, const char** texts,\n                      unsigned int num_files);\nchar* compile_paths(const char** paths, unsigned int num_paths);\n}\n"
  },
  {
    "path": "veridian-slang/src/lib.rs",
    "content": "#![allow(dead_code)]\nuse std::error;\nuse std::ffi::{CStr, CString};\nuse std::path::PathBuf;\n\nmod wrapper;\nuse wrapper::*;\n\npub fn slang_compile(paths: Vec<PathBuf>) -> Result<String, Box<dyn error::Error>> {\n    if paths.is_empty() {\n        return Ok(String::new());\n    }\n\n    // convert pathbufs to strings\n    let mut paths_str: Vec<String> = Vec::new();\n    for path in paths {\n        paths_str.push(path.to_str().unwrap().to_owned());\n    }\n    // convert strings to cstrings\n    let mut paths_c: Vec<CString> = Vec::new();\n    for path in paths_str {\n        paths_c.push(CString::new(path)?);\n    }\n    // convert cstrings to char* pointers\n    let mut paths_ptr: Vec<*const std::ffi::c_char> = paths_c.iter().map(|x| x.as_ptr()).collect();\n\n    // compile with slang, and convert report from char* to string\n    let report_raw = unsafe { compile_paths(paths_ptr.as_mut_ptr(), paths_ptr.len() as u32) };\n    let report: &CStr = unsafe { CStr::from_ptr(report_raw) };\n    let result = report.to_str()?.to_owned();\n    unsafe {\n        delete_report(report_raw);\n    }\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serial_test::serial;\n    use std::fs::File;\n    use std::io::Write;\n    use tempdir::TempDir;\n\n    #[test]\n    #[serial]\n    fn test_paths_wrapper() {\n        let dir = TempDir::new(\"slang_wrapper_tests\").unwrap();\n        let file_path_1 = dir.path().join(\"test1.sv\");\n        let mut f = File::create(&file_path_1).unwrap();\n        f.write_all(b\"module test1; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let file_path_2 = dir.path().join(\"test2.sv\");\n        let mut f = File::create(&file_path_2).unwrap();\n        f.write_all(b\"module test2; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let file_path_3 = dir.path().join(\"test3.sv\");\n        let mut f = File::create(&file_path_3).unwrap();\n        f.write_all(b\"module test3; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let mut paths: Vec<PathBuf> = Vec::new();\n        paths.push(file_path_1);\n        paths.push(file_path_2);\n        paths.push(file_path_3);\n\n        let report: String = slang_compile(paths).unwrap();\n        let mut expected =\n            \":1:43: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\n\".repeat(3);\n        expected.pop();\n        let result_iter = report.lines();\n        let mut result: String = String::new();\n        result_iter.for_each(|x| {\n            let mut y: String = x.to_owned();\n            y.replace_range(..x.find(':').unwrap(), \"\\n\");\n            result.push_str(&y);\n        });\n        // get rid of unnecessary newlines\n        result = result.trim_start().to_owned();\n        assert_eq!(result, expected);\n    }\n}\n"
  },
  {
    "path": "veridian-slang/src/wrapper.rs",
    "content": "include!(concat!(env!(\"OUT_DIR\"), \"/bindings.rs\"));\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serial_test::serial;\n    use std::ffi::{CStr, CString};\n    use std::fs::File;\n    use std::io::Write;\n    use tempdir::TempDir;\n\n    #[test]\n    #[serial]\n    fn test_path() {\n        let dir = TempDir::new(\"slang_wrapper_tests\").unwrap();\n        let file_path = dir.path().join(\"test.sv\");\n        let mut f = File::create(&file_path).unwrap();\n        f.write_all(b\"module test; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let path = CString::new(file_path.to_str().unwrap()).unwrap();\n        let report_raw = unsafe { compile_path(path.as_ptr()) };\n        let report: &CStr = unsafe { CStr::from_ptr(report_raw) };\n        let expected =\n            \":1:42: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\n\";\n        let mut result = report.to_str().unwrap().to_owned();\n        let offset = result.find(':').unwrap_or_else(|| result.len());\n        result.replace_range(..offset, \"\");\n        assert_eq!(result, expected);\n        unsafe {\n            delete_report(report_raw);\n        }\n    }\n\n    #[test]\n    #[serial]\n    fn test_paths() {\n        let dir = TempDir::new(\"slang_wrapper_tests\").unwrap();\n        let file_path_1 = dir.path().join(\"test1.sv\");\n        let file_path_1_c = CString::new(file_path_1.to_str().unwrap()).unwrap();\n        let mut f = File::create(&file_path_1).unwrap();\n        f.write_all(b\"module test1; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let file_path_2 = dir.path().join(\"test2.sv\");\n        let file_path_2_c = CString::new(file_path_2.to_str().unwrap()).unwrap();\n        let mut f = File::create(&file_path_2).unwrap();\n        f.write_all(b\"module test2; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let file_path_3 = dir.path().join(\"test3.sv\");\n        let file_path_3_c = CString::new(file_path_3.to_str().unwrap()).unwrap();\n        let mut f = File::create(&file_path_3).unwrap();\n        f.write_all(b\"module test3; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\")\n            .unwrap();\n        f.sync_all().unwrap();\n\n        let mut paths: Vec<*const i8> = Vec::new();\n        paths.push(file_path_1_c.as_ptr());\n        paths.push(file_path_2_c.as_ptr());\n        paths.push(file_path_3_c.as_ptr());\n        let report_raw = unsafe { compile_paths(paths.as_mut_ptr(), 3) };\n        let report: &CStr = unsafe { CStr::from_ptr(report_raw) };\n        let mut expected =\n            \":1:43: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\n\".repeat(3);\n        expected.pop();\n        let result_raw = report.to_str().unwrap().to_owned();\n        let result_iter = result_raw.lines();\n        let mut result: String = String::new();\n        result_iter.for_each(|x| {\n            let mut y: String = x.to_owned();\n            y.replace_range(..x.find(\":\").unwrap(), \"\\n\");\n            result.push_str(&y);\n        });\n        // get rid of unnecessary newlines\n        result = result.trim_start().to_owned();\n        assert_eq!(result, expected);\n        unsafe {\n            delete_report(report_raw);\n        }\n    }\n\n    #[test]\n    #[serial]\n    fn test_compilation_multi() {\n        let mut names: Vec<*const i8> = Vec::new();\n        let mut texts: Vec<*const i8> = Vec::new();\n        let name1 = CString::new(\"test1.sv\").unwrap();\n        let name2 = CString::new(\"test2.sv\").unwrap();\n        let name3 = CString::new(\"test3.sv\").unwrap();\n        names.push(name1.as_ptr());\n        names.push(name2.as_ptr());\n        names.push(name3.as_ptr());\n        let text1 =\n            CString::new(\"module test1; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\").unwrap();\n        let text2 =\n            CString::new(\"module test2; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\").unwrap();\n        let text3 =\n            CString::new(\"module test3; logic [1:0] abc; assign abc[2] = 1'b1; endmodule\").unwrap();\n        texts.push(text1.as_ptr());\n        texts.push(text2.as_ptr());\n        texts.push(text3.as_ptr());\n\n        let report_raw = unsafe { compile_sources(names.as_mut_ptr(), texts.as_mut_ptr(), 3) };\n        let report: &CStr = unsafe { CStr::from_ptr(report_raw) };\n        let expected = \"test1.sv:1:43: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\ntest2.sv:1:43: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\ntest3.sv:1:43: warning: cannot refer to element 2 of \\'logic[1:0]\\' [-Windex-oob]\\n\";\n        let result = report.to_str().unwrap();\n        assert_eq!(result, expected);\n        unsafe {\n            delete_report(report_raw);\n        }\n    }\n}\n"
  }
]